docs: new website initial commit
Co-authored-by: Giorgio Boa <35845425+gioboa@users.noreply.github.com> Co-authored-by: Jovana Đurić <63621526+jovanadjuric@users.noreply.github.com> Co-authored-by: jovanadjuric <mat.jovana@gmail.com> Co-authored-by: Mike Guida <mike@mguida.com> Co-authored-by: gioboa <giorgiob.boa@gmail.com>
2
.github/workflows/docsearch.yml
vendored
@ -21,4 +21,4 @@ jobs:
|
||||
-e TYPESENSE_PORT="443" \
|
||||
-e TYPESENSE_PROTOCOL="https" \
|
||||
-e CONFIG="$(cat docs/docsearch-scraper-config.json | jq -r tostring)" \
|
||||
typesense/docsearch-scraper
|
||||
typesense/docsearch-scraper
|
||||
|
||||
49
CHANGELOG.md
@ -80,41 +80,35 @@ await repository.clear()
|
||||
|
||||
## [0.3.22](https://github.com/typeorm/typeorm/compare/0.3.21...0.3.22) (2025-04-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* bulk insert NULL values in Oracle ([#11363](https://github.com/typeorm/typeorm/issues/11363)) ([bcaa0bf](https://github.com/typeorm/typeorm/commit/bcaa0bf0714c271a35e02cd4a512618a5eedccce))
|
||||
* ensure correct MSSQL parameter conversion in where conditions ([ecae9f5](https://github.com/typeorm/typeorm/commit/ecae9f599066947ad1515bf6e55c2fdfbd3bf3f9)), closes [#11285](https://github.com/typeorm/typeorm/issues/11285)
|
||||
* export QueryEvent before/after types ([#10688](https://github.com/typeorm/typeorm/issues/10688)) ([03dbc7a](https://github.com/typeorm/typeorm/commit/03dbc7a697f6fae2be77585030245a5877b8b33e))
|
||||
* FindOptionsSelect to use correct type when property is an object ([#11355](https://github.com/typeorm/typeorm/issues/11355)) ([834e856](https://github.com/typeorm/typeorm/commit/834e85692f8bb0d6edc2bfed601717e57ac7dcb7))
|
||||
* incorrect table alias in insert orUpdate with Postgres driver ([#11082](https://github.com/typeorm/typeorm/issues/11082)) ([72c6991](https://github.com/typeorm/typeorm/commit/72c6991680b39a39799c005914e16b127c8ab805)), closes [#11077](https://github.com/typeorm/typeorm/issues/11077)
|
||||
* inverse relation metadata not cyclic ([50a660a](https://github.com/typeorm/typeorm/commit/50a660aecc9d34c3985d4460f05b8ffe52450549))
|
||||
* remove unnecessary import from JS migration ([#11327](https://github.com/typeorm/typeorm/issues/11327)) ([72145b8](https://github.com/typeorm/typeorm/commit/72145b859d52094f77a043b80f9235955bf6ff01))
|
||||
* remove unnecessary spaces in message when running non-fake migrations ([#10809](https://github.com/typeorm/typeorm/issues/10809)) ([c3bebdc](https://github.com/typeorm/typeorm/commit/c3bebdcb4e9bd2a501bebec39ec22465ae7a3305))
|
||||
* **sap:** incorrect handling of simple array/json data type ([#11322](https://github.com/typeorm/typeorm/issues/11322)) ([27b4207](https://github.com/typeorm/typeorm/commit/27b4207c48a391c7bf7013b251f756f48861c496))
|
||||
* **sap:** normalize deprecated/removed data types in SAP HANA Cloud ([#11356](https://github.com/typeorm/typeorm/issues/11356)) ([460ef02](https://github.com/typeorm/typeorm/commit/460ef023bad9b5333c8ea01d3143a4f1e9128d9e))
|
||||
* **sap:** pass the configured schema to the db client ([#11321](https://github.com/typeorm/typeorm/issues/11321)) ([04ca83a](https://github.com/typeorm/typeorm/commit/04ca83a72f03f7afcad0e7b7f8c9bf60291a87a9))
|
||||
* sql escape issues identified by CodeQL ([#11338](https://github.com/typeorm/typeorm/issues/11338)) ([863caf1](https://github.com/typeorm/typeorm/commit/863caf1471e87f18f170492ab8642e51845912ce))
|
||||
* update mongodb connection options ([#11310](https://github.com/typeorm/typeorm/issues/11310)) ([81bb9d5](https://github.com/typeorm/typeorm/commit/81bb9d53e898f977ccf1ed16f09d1c860303a8f5))
|
||||
* version detection for Postgres derived variants ([#11375](https://github.com/typeorm/typeorm/issues/11375)) ([3d79786](https://github.com/typeorm/typeorm/commit/3d79786a926f12416755bff1eb340d68577c40ed))
|
||||
|
||||
- bulk insert NULL values in Oracle ([#11363](https://github.com/typeorm/typeorm/issues/11363)) ([bcaa0bf](https://github.com/typeorm/typeorm/commit/bcaa0bf0714c271a35e02cd4a512618a5eedccce))
|
||||
- ensure correct MSSQL parameter conversion in where conditions ([ecae9f5](https://github.com/typeorm/typeorm/commit/ecae9f599066947ad1515bf6e55c2fdfbd3bf3f9)), closes [#11285](https://github.com/typeorm/typeorm/issues/11285)
|
||||
- export QueryEvent before/after types ([#10688](https://github.com/typeorm/typeorm/issues/10688)) ([03dbc7a](https://github.com/typeorm/typeorm/commit/03dbc7a697f6fae2be77585030245a5877b8b33e))
|
||||
- FindOptionsSelect to use correct type when property is an object ([#11355](https://github.com/typeorm/typeorm/issues/11355)) ([834e856](https://github.com/typeorm/typeorm/commit/834e85692f8bb0d6edc2bfed601717e57ac7dcb7))
|
||||
- incorrect table alias in insert orUpdate with Postgres driver ([#11082](https://github.com/typeorm/typeorm/issues/11082)) ([72c6991](https://github.com/typeorm/typeorm/commit/72c6991680b39a39799c005914e16b127c8ab805)), closes [#11077](https://github.com/typeorm/typeorm/issues/11077)
|
||||
- inverse relation metadata not cyclic ([50a660a](https://github.com/typeorm/typeorm/commit/50a660aecc9d34c3985d4460f05b8ffe52450549))
|
||||
- remove unnecessary import from JS migration ([#11327](https://github.com/typeorm/typeorm/issues/11327)) ([72145b8](https://github.com/typeorm/typeorm/commit/72145b859d52094f77a043b80f9235955bf6ff01))
|
||||
- remove unnecessary spaces in message when running non-fake migrations ([#10809](https://github.com/typeorm/typeorm/issues/10809)) ([c3bebdc](https://github.com/typeorm/typeorm/commit/c3bebdcb4e9bd2a501bebec39ec22465ae7a3305))
|
||||
- **sap:** incorrect handling of simple array/json data type ([#11322](https://github.com/typeorm/typeorm/issues/11322)) ([27b4207](https://github.com/typeorm/typeorm/commit/27b4207c48a391c7bf7013b251f756f48861c496))
|
||||
- **sap:** normalize deprecated/removed data types in SAP HANA Cloud ([#11356](https://github.com/typeorm/typeorm/issues/11356)) ([460ef02](https://github.com/typeorm/typeorm/commit/460ef023bad9b5333c8ea01d3143a4f1e9128d9e))
|
||||
- **sap:** pass the configured schema to the db client ([#11321](https://github.com/typeorm/typeorm/issues/11321)) ([04ca83a](https://github.com/typeorm/typeorm/commit/04ca83a72f03f7afcad0e7b7f8c9bf60291a87a9))
|
||||
- sql escape issues identified by CodeQL ([#11338](https://github.com/typeorm/typeorm/issues/11338)) ([863caf1](https://github.com/typeorm/typeorm/commit/863caf1471e87f18f170492ab8642e51845912ce))
|
||||
- update mongodb connection options ([#11310](https://github.com/typeorm/typeorm/issues/11310)) ([81bb9d5](https://github.com/typeorm/typeorm/commit/81bb9d53e898f977ccf1ed16f09d1c860303a8f5))
|
||||
- version detection for Postgres derived variants ([#11375](https://github.com/typeorm/typeorm/issues/11375)) ([3d79786](https://github.com/typeorm/typeorm/commit/3d79786a926f12416755bff1eb340d68577c40ed))
|
||||
|
||||
### Features
|
||||
|
||||
* **postgres:** support macaddr8 column type ([b0ea913](https://github.com/typeorm/typeorm/commit/b0ea913f4ef903590221dee3699dbd39b6fc9986))
|
||||
* Send DriverInfo to MongoDB client ([#11214](https://github.com/typeorm/typeorm/issues/11214)) ([a29e047](https://github.com/typeorm/typeorm/commit/a29e04750dffffe76c1646d3b3050499576b5dc3))
|
||||
* Support Expo SQLite Next ([7b242e1](https://github.com/typeorm/typeorm/commit/7b242e1698e1188c6a0899667c71f16fffe9ddb7))
|
||||
|
||||
- **postgres:** support macaddr8 column type ([b0ea913](https://github.com/typeorm/typeorm/commit/b0ea913f4ef903590221dee3699dbd39b6fc9986))
|
||||
- Send DriverInfo to MongoDB client ([#11214](https://github.com/typeorm/typeorm/issues/11214)) ([a29e047](https://github.com/typeorm/typeorm/commit/a29e04750dffffe76c1646d3b3050499576b5dc3))
|
||||
- Support Expo SQLite Next ([7b242e1](https://github.com/typeorm/typeorm/commit/7b242e1698e1188c6a0899667c71f16fffe9ddb7))
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "fix: nested transactions issues (#10210)" ([7aa4f3c](https://github.com/typeorm/typeorm/commit/7aa4f3c3e05f5b2ec262b31af32864dc16ef7c82)), closes [#10210](https://github.com/typeorm/typeorm/issues/10210)
|
||||
|
||||
|
||||
- Revert "fix: nested transactions issues (#10210)" ([7aa4f3c](https://github.com/typeorm/typeorm/commit/7aa4f3c3e05f5b2ec262b31af32864dc16ef7c82)), closes [#10210](https://github.com/typeorm/typeorm/issues/10210)
|
||||
|
||||
## [0.3.21](https://github.com/typeorm/typeorm/compare/v0.3.20...v0.3.21) (2025-03-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Add support for better-sqlite3 v10 and 11 ([#11096](https://github.com/typeorm/typeorm/issues/11096)) ([6c0c2ba](https://github.com/typeorm/typeorm/commit/6c0c2bab63b0b88086cfc14d090c33a05aa66ac7))
|
||||
@ -126,13 +120,10 @@ await repository.clear()
|
||||
- Fix maximum call stack error ([#10733](https://github.com/typeorm/typeorm/issues/10733)) ([7a384be0](https://github.com/typeorm/typeorm/commit/7a384be0f64630a6891528a0b2b466136752f588))
|
||||
- use sql-highlight instead of cli-highlight ([#11221](https://github.com/typeorm/typeorm/issues/11221)) ([1516cfe](https://github.com/typeorm/typeorm/commit/1516cfebdd34739f723d65030eb9540a44d786b2))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
- improve results transformer performance ([#10349](https://github.com/typeorm/typeorm/issues/10349)) ([7bea198](https://github.com/typeorm/typeorm/commit/7bea198b9bc5688647d089eed03e1639116766b6))
|
||||
|
||||
|
||||
|
||||
## [0.3.20](https://github.com/typeorm/typeorm/compare/0.3.19...0.3.20) (2024-01-26)
|
||||
|
||||
### Bug Fixes
|
||||
@ -1878,7 +1869,7 @@ export const MyDataSources = {
|
||||
### Features
|
||||
|
||||
- added deferrable options for foreign keys (postgres) ([#2191](https://github.com/typeorm/typeorm/issues/2191))
|
||||
- added View entity implementation ([#1024](https://github.com/typeorm/typeorm/issues/1024)). Read more at [View entities](https://typeorm.io/#/view-entities)
|
||||
- added View entity implementation ([#1024](https://github.com/typeorm/typeorm/issues/1024)). Read more at [View entities](https://typeorm.io/docs/entity/view-entities/)
|
||||
- added multiple value transformer support ([#4007](https://github.com/typeorm/typeorm/issues/4007))
|
||||
|
||||
## 0.2.16 (2019-03-26)
|
||||
@ -2196,7 +2187,7 @@ stringEnums: StringEnum[];
|
||||
- added support for more complex ordering in paginated results ([#1259](https://github.com/typeorm/typeorm/issues/1259))
|
||||
- MSSQL users are required to add "order by" for skip/offset operations since mssql does not support OFFSET/LIMIT statement without order by applied
|
||||
- fixed issue when relation query builder methods execute operations with empty arrays ([#1241](https://github.com/typeorm/typeorm/issues/1241))
|
||||
- Webpack can now be used for node projects and not only for browser projects. To use TypeORM in Ionic with minimal changes checkout the [ionic-example](https://github.com/typeorm/ionic-example#typeorm--017) for the needed changes. To use webpack for non-Ionic browser webpack projects, the needed configuration can be found in the [docs](http://typeorm.io/#/supported-platforms) ([#1280](https://github.com/typeorm/typeorm/pulls/1280))
|
||||
- Webpack can now be used for node projects and not only for browser projects. To use TypeORM in Ionic with minimal changes checkout the [ionic-example](https://github.com/typeorm/ionic-example#typeorm--017) for the needed changes. To use webpack for non-Ionic browser webpack projects, the needed configuration can be found in the [docs](http://typeorm.io/docs/help/supported-platforms) ([#1280](https://github.com/typeorm/typeorm/pulls/1280))
|
||||
- added support for loading sub-relations in via find options ([#1270](https://github.com/typeorm/typeorm/issues/1270))
|
||||
|
||||
## 0.1.6
|
||||
|
||||
988
README-zh_CN.md
18
README.md
@ -29,7 +29,7 @@ that help you to develop any kind of application that uses databases - from
|
||||
small applications with a few tables to large-scale enterprise applications
|
||||
with multiple databases.
|
||||
|
||||
TypeORM supports both [Active Record](./docs/active-record-data-mapper.md#what-is-the-active-record-pattern) and [Data Mapper](./docs/active-record-data-mapper.md#what-is-the-data-mapper-pattern) patterns,
|
||||
TypeORM supports both [Active Record](./docs/docs/guides/1-active-record-data-mapper.md#what-is-the-active-record-pattern) and [Data Mapper](./docs/docs/guides/1-active-record-data-mapper.md#what-is-the-data-mapper-pattern) patterns,
|
||||
unlike all other JavaScript ORMs currently in existence,
|
||||
which means you can write high-quality, loosely coupled, scalable,
|
||||
maintainable applications in the most productive way.
|
||||
@ -39,7 +39,7 @@ TypeORM is highly influenced by other ORMs, such as [Hibernate](http://hibernate
|
||||
|
||||
## Features
|
||||
|
||||
- Supports both [DataMapper](./docs/active-record-data-mapper.md#what-is-the-data-mapper-pattern) and [ActiveRecord](./docs/active-record-data-mapper.md#what-is-the-active-record-pattern) (your choice).
|
||||
- Supports both [DataMapper](./docs/docs/guides/1-active-record-data-mapper.md#what-is-the-data-mapper-pattern) and [ActiveRecord](./docs/docs/guides/1-active-record-data-mapper.md#what-is-the-active-record-pattern) (your choice).
|
||||
- Entities and columns.
|
||||
- Database-specific column types.
|
||||
- Entity manager.
|
||||
@ -158,7 +158,7 @@ const firstUser = await User.findOneBy({
|
||||
})
|
||||
const timber = await User.findOneBy({
|
||||
firstName: "Timber",
|
||||
lastName: "Saw"
|
||||
lastName: "Saw",
|
||||
})
|
||||
|
||||
await timber.remove()
|
||||
@ -255,7 +255,7 @@ await timber.remove()
|
||||
|
||||
- for **NativeScript**, **react-native** and **Cordova**
|
||||
|
||||
Check [documentation of supported platforms](./docs/supported-platforms.md)
|
||||
Check [documentation of supported platforms](./docs/docs/help/2-supported-platforms.md)
|
||||
|
||||
Install only _one_ of them, depending on which database you use.
|
||||
|
||||
@ -547,7 +547,7 @@ export class Photo {
|
||||
|
||||
Column types are database-specific.
|
||||
You can set any column type your database supports.
|
||||
More information on supported column types can be found [here](./docs/entities.md#column-types).
|
||||
More information on supported column types can be found [here](./docs/docs/entity/1-entities.md#column-types).
|
||||
|
||||
### Creating a new `DataSource`
|
||||
|
||||
@ -648,7 +648,7 @@ console.log("All photos from the db: ", savedPhotos)
|
||||
|
||||
`savedPhotos` will be an array of Photo objects with the data loaded from the database.
|
||||
|
||||
Learn more about EntityManager [here](./docs/working-with-entity-manager.md).
|
||||
Learn more about EntityManager [here](./docs/docs/working-with-entity-manager/1-working-with-entity-manager.md).
|
||||
|
||||
### Using Repositories
|
||||
|
||||
@ -676,7 +676,7 @@ const savedPhotos = await photoRepository.find()
|
||||
console.log("All photos from the db: ", savedPhotos)
|
||||
```
|
||||
|
||||
Learn more about Repository [here](./docs/working-with-repository.md).
|
||||
Learn more about Repository [here](./docs/docs/working-with-entity-manager/2-working-with-repository.md).
|
||||
|
||||
### Loading from the database
|
||||
|
||||
@ -966,7 +966,7 @@ const photos = await photoRepository.find({
|
||||
```
|
||||
|
||||
Here, photos will contain an array of photos from the database, and each photo will contain its photo metadata.
|
||||
Learn more about Find Options in [this documentation](./docs/find-options.md).
|
||||
Learn more about Find Options in [this documentation](./docs/docs/working-with-entity-manager/3-find-options.md).
|
||||
|
||||
Using find options is good and dead simple, but if you need a more complex query, you should use `QueryBuilder` instead.
|
||||
`QueryBuilder` allows more complex queries to be used in an elegant way:
|
||||
@ -1255,7 +1255,7 @@ The selection result will be ordered by id in descending order.
|
||||
The photo albums will be left joined and their metadata will be inner joined.
|
||||
|
||||
You'll use the query builder in your application a lot.
|
||||
Learn more about QueryBuilder [here](./docs/select-query-builder.md).
|
||||
Learn more about QueryBuilder [here](./docs/docs/query-builder/1-select-query-builder.md).
|
||||
|
||||
## Samples
|
||||
|
||||
|
||||
836
README_ko.md
20
docs/.gitignore
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
# Dependencies
|
||||
/node_modules
|
||||
|
||||
# Production
|
||||
/build
|
||||
|
||||
# Generated files
|
||||
.docusaurus
|
||||
.cache-loader
|
||||
|
||||
# Misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
41
docs/README.md
Normal file
@ -0,0 +1,41 @@
|
||||
# Website
|
||||
|
||||
This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator.
|
||||
|
||||
### Installation
|
||||
|
||||
```
|
||||
$ npm install
|
||||
```
|
||||
|
||||
### Local Development
|
||||
|
||||
```
|
||||
$ npm run start
|
||||
```
|
||||
|
||||
This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
|
||||
|
||||
### Build
|
||||
|
||||
```
|
||||
$ npm run build
|
||||
```
|
||||
|
||||
This command generates static content into the `build` directory and can be served using any static contents hosting service.
|
||||
|
||||
### Deployment
|
||||
|
||||
Using SSH:
|
||||
|
||||
```
|
||||
$ USE_SSH=true npm deploy
|
||||
```
|
||||
|
||||
Not using SSH:
|
||||
|
||||
```
|
||||
$ GIT_USER=<Your GitHub username> npm deploy
|
||||
```
|
||||
|
||||
If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.
|
||||
@ -1,17 +1,6 @@
|
||||
# Migrations
|
||||
|
||||
- [Migrations](#migrations)
|
||||
- [How migrations work](#how-migrations-work)
|
||||
- [Creating a new migration](#creating-a-new-migration)
|
||||
- [Running and reverting migrations](#running-and-reverting-migrations)
|
||||
- [Faking Migrations and Rollbacks](#faking-migrations-and-rollbacks)
|
||||
- [Transaction modes](#transaction-modes)
|
||||
- [Generating migrations](#generating-migrations)
|
||||
- [DataSource option](#datasource-option)
|
||||
- [Timestamp option](#timestamp-option)
|
||||
- [Using migration API to write migrations](#using-migration-api-to-write-migrations)
|
||||
|
||||
## How migrations work
|
||||
## How migrations work?
|
||||
|
||||
Once you get into production you'll need to synchronize model changes into the database.
|
||||
Typically, it is unsafe to use `synchronize: true` for schema synchronization on production once
|
||||
@ -56,7 +45,7 @@ This place is called "migrations".
|
||||
|
||||
## Creating a new migration
|
||||
|
||||
**Pre-requisites**: [Installing CLI](./using-cli.md#installing-cli)
|
||||
**Pre-requisites**: [Installing CLI](./6-using-cli.md#installing-cli)
|
||||
|
||||
Before creating a new migration you need to setup your data source options properly:
|
||||
|
||||
@ -82,8 +71,8 @@ export default new DataSource({
|
||||
|
||||
Here we setup two options:
|
||||
|
||||
- `"migrationsTableName": "migrations"` - Specify this option only if you need the migration table name to be different from `"migrations"`.
|
||||
- `"migrations": [/*...*/]` - list of migrations that need to be loaded by TypeORM
|
||||
- `"migrationsTableName": "migrations"` - Specify this option only if you need the migration table name to be different from `"migrations"`.
|
||||
- `"migrations": [/*...*/]` - list of migrations that need to be loaded by TypeORM
|
||||
|
||||
Once you setup the connection options you can create a new migration using CLI:
|
||||
|
||||
@ -116,7 +105,7 @@ There are two methods you must fill with your migration code: `up` and `down`.
|
||||
|
||||
Inside both `up` and `down` you have a `QueryRunner` object.
|
||||
All database operations are executed using this object.
|
||||
Learn more about [query runner](./query-runner.md).
|
||||
Learn more about [query runner](../query-runner.md).
|
||||
|
||||
Let's see what the migration looks like with our `Post` changes:
|
||||
|
||||
@ -310,6 +299,32 @@ export class PostRefactoringTIMESTAMP {
|
||||
}
|
||||
```
|
||||
|
||||
By default, it generates CommonJS JavaScript code with the `o` (alias for `--outputJs`) flag, but you can also generate ESM code with the `esm` flag. This is useful for Javascript projects that use ESM:
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* @typedef {import('typeorm').MigrationInterface} MigrationInterface
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @implements {MigrationInterface}
|
||||
*/
|
||||
export class PostRefactoringTIMESTAMP {
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "post" ALTER COLUMN "title" RENAME TO "name"`,
|
||||
)
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "post" ALTER COLUMN "name" RENAME TO "title"`,
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See, you don't need to write the queries on your own.
|
||||
The rule of thumb for generating migrations is that you generate them after **each** change you made to your models. To apply multi-line formatting to your generated migration queries, use the `p` (alias for `--pretty`) flag.
|
||||
|
||||
@ -450,7 +465,7 @@ Returns all available database names including system databases.
|
||||
getSchemas(database?: string): Promise<string[]>
|
||||
```
|
||||
|
||||
- `database` - If database parameter specified, returns schemas of that database
|
||||
- `database` - If database parameter specified, returns schemas of that database
|
||||
|
||||
Returns all available schema names including system schemas. Useful for SQLServer and Postgres only.
|
||||
|
||||
@ -460,7 +475,7 @@ Returns all available schema names including system schemas. Useful for SQLServe
|
||||
getTable(tableName: string): Promise<Table|undefined>
|
||||
```
|
||||
|
||||
- `tableName` - name of a table to be loaded
|
||||
- `tableName` - name of a table to be loaded
|
||||
|
||||
Loads a table by a given name from the database.
|
||||
|
||||
@ -470,7 +485,7 @@ Loads a table by a given name from the database.
|
||||
getTables(tableNames: string[]): Promise<Table[]>
|
||||
```
|
||||
|
||||
- `tableNames` - name of a tables to be loaded
|
||||
- `tableNames` - name of a tables to be loaded
|
||||
|
||||
Loads a tables by a given names from the database.
|
||||
|
||||
@ -480,7 +495,7 @@ Loads a tables by a given names from the database.
|
||||
hasDatabase(database: string): Promise<boolean>
|
||||
```
|
||||
|
||||
- `database` - name of a database to be checked
|
||||
- `database` - name of a database to be checked
|
||||
|
||||
Checks if database with the given name exist.
|
||||
|
||||
@ -490,7 +505,7 @@ Checks if database with the given name exist.
|
||||
hasSchema(schema: string): Promise<boolean>
|
||||
```
|
||||
|
||||
- `schema` - name of a schema to be checked
|
||||
- `schema` - name of a schema to be checked
|
||||
|
||||
Checks if schema with the given name exist. Used only for SqlServer and Postgres.
|
||||
|
||||
@ -500,7 +515,7 @@ Checks if schema with the given name exist. Used only for SqlServer and Postgres
|
||||
hasTable(table: Table|string): Promise<boolean>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `table` - Table object or name
|
||||
|
||||
Checks if table exist.
|
||||
|
||||
@ -510,8 +525,8 @@ Checks if table exist.
|
||||
hasColumn(table: Table|string, columnName: string): Promise<boolean>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `columnName` - name of a column to be checked
|
||||
- `table` - Table object or name
|
||||
- `columnName` - name of a column to be checked
|
||||
|
||||
Checks if column exist in the table.
|
||||
|
||||
@ -521,8 +536,8 @@ Checks if column exist in the table.
|
||||
createDatabase(database: string, ifNotExist?: boolean): Promise<void>
|
||||
```
|
||||
|
||||
- `database` - database name
|
||||
- `ifNotExist` - skips creation if `true`, otherwise throws error if database already exist
|
||||
- `database` - database name
|
||||
- `ifNotExist` - skips creation if `true`, otherwise throws error if database already exist
|
||||
|
||||
Creates a new database.
|
||||
|
||||
@ -532,8 +547,8 @@ Creates a new database.
|
||||
dropDatabase(database: string, ifExist?: boolean): Promise<void>
|
||||
```
|
||||
|
||||
- `database` - database name
|
||||
- `ifExist` - skips deletion if `true`, otherwise throws error if database was not found
|
||||
- `database` - database name
|
||||
- `ifExist` - skips deletion if `true`, otherwise throws error if database was not found
|
||||
|
||||
Drops database.
|
||||
|
||||
@ -543,9 +558,9 @@ Drops database.
|
||||
createSchema(schemaPath: string, ifNotExist?: boolean): Promise<void>
|
||||
```
|
||||
|
||||
- `schemaPath` - schema name. For SqlServer can accept schema path (e.g. 'dbName.schemaName') as parameter.
|
||||
If schema path passed, it will create schema in specified database
|
||||
- `ifNotExist` - skips creation if `true`, otherwise throws error if schema already exist
|
||||
- `schemaPath` - schema name. For SqlServer can accept schema path (e.g. 'dbName.schemaName') as parameter.
|
||||
If schema path passed, it will create schema in specified database
|
||||
- `ifNotExist` - skips creation if `true`, otherwise throws error if schema already exist
|
||||
|
||||
Creates a new table schema.
|
||||
|
||||
@ -555,11 +570,11 @@ Creates a new table schema.
|
||||
dropSchema(schemaPath: string, ifExist?: boolean, isCascade?: boolean): Promise<void>
|
||||
```
|
||||
|
||||
- `schemaPath` - schema name. For SqlServer can accept schema path (e.g. 'dbName.schemaName') as parameter.
|
||||
If schema path passed, it will drop schema in specified database
|
||||
- `ifExist` - skips deletion if `true`, otherwise throws error if schema was not found
|
||||
- `isCascade` - If `true`, automatically drop objects (tables, functions, etc.) that are contained in the schema.
|
||||
Used only in Postgres.
|
||||
- `schemaPath` - schema name. For SqlServer can accept schema path (e.g. 'dbName.schemaName') as parameter.
|
||||
If schema path passed, it will drop schema in specified database
|
||||
- `ifExist` - skips deletion if `true`, otherwise throws error if schema was not found
|
||||
- `isCascade` - If `true`, automatically drop objects (tables, functions, etc.) that are contained in the schema.
|
||||
Used only in Postgres.
|
||||
|
||||
Drops a table schema.
|
||||
|
||||
@ -569,10 +584,10 @@ Drops a table schema.
|
||||
createTable(table: Table, ifNotExist?: boolean, createForeignKeys?: boolean, createIndices?: boolean): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object.
|
||||
- `ifNotExist` - skips creation if `true`, otherwise throws error if table already exist. Default `false`
|
||||
- `createForeignKeys` - indicates whether foreign keys will be created on table creation. Default `true`
|
||||
- `createIndices` - indicates whether indices will be created on table creation. Default `true`
|
||||
- `table` - Table object.
|
||||
- `ifNotExist` - skips creation if `true`, otherwise throws error if table already exist. Default `false`
|
||||
- `createForeignKeys` - indicates whether foreign keys will be created on table creation. Default `true`
|
||||
- `createIndices` - indicates whether indices will be created on table creation. Default `true`
|
||||
|
||||
Creates a new table.
|
||||
|
||||
@ -582,10 +597,10 @@ Creates a new table.
|
||||
dropTable(table: Table|string, ifExist?: boolean, dropForeignKeys?: boolean, dropIndices?: boolean): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or table name to be dropped
|
||||
- `ifExist` - skips dropping if `true`, otherwise throws error if table does not exist
|
||||
- `dropForeignKeys` - indicates whether foreign keys will be dropped on table deletion. Default `true`
|
||||
- `dropIndices` - indicates whether indices will be dropped on table deletion. Default `true`
|
||||
- `table` - Table object or table name to be dropped
|
||||
- `ifExist` - skips dropping if `true`, otherwise throws error if table does not exist
|
||||
- `dropForeignKeys` - indicates whether foreign keys will be dropped on table deletion. Default `true`
|
||||
- `dropIndices` - indicates whether indices will be dropped on table deletion. Default `true`
|
||||
|
||||
Drops a table.
|
||||
|
||||
@ -595,8 +610,8 @@ Drops a table.
|
||||
renameTable(oldTableOrName: Table|string, newTableName: string): Promise<void>
|
||||
```
|
||||
|
||||
- `oldTableOrName` - old Table object or name to be renamed
|
||||
- `newTableName` - new table name
|
||||
- `oldTableOrName` - old Table object or name to be renamed
|
||||
- `newTableName` - new table name
|
||||
|
||||
Renames a table.
|
||||
|
||||
@ -606,8 +621,8 @@ Renames a table.
|
||||
addColumn(table: Table|string, column: TableColumn): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `column` - new column
|
||||
- `table` - Table object or name
|
||||
- `column` - new column
|
||||
|
||||
Adds a new column.
|
||||
|
||||
@ -617,8 +632,8 @@ Adds a new column.
|
||||
addColumns(table: Table|string, columns: TableColumn[]): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `columns` - new columns
|
||||
- `table` - Table object or name
|
||||
- `columns` - new columns
|
||||
|
||||
Adds a new column.
|
||||
|
||||
@ -628,9 +643,9 @@ Adds a new column.
|
||||
renameColumn(table: Table|string, oldColumnOrName: TableColumn|string, newColumnOrName: TableColumn|string): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `oldColumnOrName` - old column. Accepts TableColumn object or column name
|
||||
- `newColumnOrName` - new column. Accepts TableColumn object or column name
|
||||
- `table` - Table object or name
|
||||
- `oldColumnOrName` - old column. Accepts TableColumn object or column name
|
||||
- `newColumnOrName` - new column. Accepts TableColumn object or column name
|
||||
|
||||
Renames a column.
|
||||
|
||||
@ -640,9 +655,9 @@ Renames a column.
|
||||
changeColumn(table: Table|string, oldColumn: TableColumn|string, newColumn: TableColumn): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `oldColumn` - old column. Accepts TableColumn object or column name
|
||||
- `newColumn` - new column. Accepts TableColumn object
|
||||
- `table` - Table object or name
|
||||
- `oldColumn` - old column. Accepts TableColumn object or column name
|
||||
- `newColumn` - new column. Accepts TableColumn object
|
||||
|
||||
Changes a column in the table.
|
||||
|
||||
@ -652,10 +667,10 @@ Changes a column in the table.
|
||||
changeColumns(table: Table|string, changedColumns: { oldColumn: TableColumn, newColumn: TableColumn }[]): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `changedColumns` - array of changed columns.
|
||||
- `oldColumn` - old TableColumn object
|
||||
- `newColumn` - new TableColumn object
|
||||
- `table` - Table object or name
|
||||
- `changedColumns` - array of changed columns.
|
||||
- `oldColumn` - old TableColumn object
|
||||
- `newColumn` - new TableColumn object
|
||||
|
||||
Changes a columns in the table.
|
||||
|
||||
@ -665,8 +680,8 @@ Changes a columns in the table.
|
||||
dropColumn(table: Table|string, column: TableColumn|string): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `column` - TableColumn object or column name to be dropped
|
||||
- `table` - Table object or name
|
||||
- `column` - TableColumn object or column name to be dropped
|
||||
|
||||
Drops a column in the table.
|
||||
|
||||
@ -676,8 +691,8 @@ Drops a column in the table.
|
||||
dropColumns(table: Table|string, columns: TableColumn[]|string[]): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `columns` - array of TableColumn objects or column names to be dropped
|
||||
- `table` - Table object or name
|
||||
- `columns` - array of TableColumn objects or column names to be dropped
|
||||
|
||||
Drops a columns in the table.
|
||||
|
||||
@ -687,8 +702,8 @@ Drops a columns in the table.
|
||||
createPrimaryKey(table: Table|string, columnNames: string[]): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `columnNames` - array of column names which will be primary
|
||||
- `table` - Table object or name
|
||||
- `columnNames` - array of column names which will be primary
|
||||
|
||||
Creates a new primary key.
|
||||
|
||||
@ -698,8 +713,8 @@ Creates a new primary key.
|
||||
updatePrimaryKeys(table: Table|string, columns: TableColumn[]): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `columns` - array of TableColumn objects which will be updated
|
||||
- `table` - Table object or name
|
||||
- `columns` - array of TableColumn objects which will be updated
|
||||
|
||||
Updates composite primary keys.
|
||||
|
||||
@ -709,7 +724,7 @@ Updates composite primary keys.
|
||||
dropPrimaryKey(table: Table|string): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `table` - Table object or name
|
||||
|
||||
Drops a primary key.
|
||||
|
||||
@ -719,8 +734,8 @@ Drops a primary key.
|
||||
createUniqueConstraint(table: Table|string, uniqueConstraint: TableUnique): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `uniqueConstraint` - TableUnique object to be created
|
||||
- `table` - Table object or name
|
||||
- `uniqueConstraint` - TableUnique object to be created
|
||||
|
||||
Creates new unique constraint.
|
||||
|
||||
@ -732,8 +747,8 @@ Creates new unique constraint.
|
||||
createUniqueConstraints(table: Table|string, uniqueConstraints: TableUnique[]): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `uniqueConstraints` - array of TableUnique objects to be created
|
||||
- `table` - Table object or name
|
||||
- `uniqueConstraints` - array of TableUnique objects to be created
|
||||
|
||||
Creates new unique constraints.
|
||||
|
||||
@ -745,8 +760,8 @@ Creates new unique constraints.
|
||||
dropUniqueConstraint(table: Table|string, uniqueOrName: TableUnique|string): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `uniqueOrName` - TableUnique object or unique constraint name to be dropped
|
||||
- `table` - Table object or name
|
||||
- `uniqueOrName` - TableUnique object or unique constraint name to be dropped
|
||||
|
||||
Drops an unique constraint.
|
||||
|
||||
@ -758,8 +773,8 @@ Drops an unique constraint.
|
||||
dropUniqueConstraints(table: Table|string, uniqueConstraints: TableUnique[]): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `uniqueConstraints` - array of TableUnique objects to be dropped
|
||||
- `table` - Table object or name
|
||||
- `uniqueConstraints` - array of TableUnique objects to be dropped
|
||||
|
||||
Drops an unique constraints.
|
||||
|
||||
@ -771,8 +786,8 @@ Drops an unique constraints.
|
||||
createCheckConstraint(table: Table|string, checkConstraint: TableCheck): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `checkConstraint` - TableCheck object
|
||||
- `table` - Table object or name
|
||||
- `checkConstraint` - TableCheck object
|
||||
|
||||
Creates new check constraint.
|
||||
|
||||
@ -784,8 +799,8 @@ Creates new check constraint.
|
||||
createCheckConstraints(table: Table|string, checkConstraints: TableCheck[]): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `checkConstraints` - array of TableCheck objects
|
||||
- `table` - Table object or name
|
||||
- `checkConstraints` - array of TableCheck objects
|
||||
|
||||
Creates new check constraint.
|
||||
|
||||
@ -797,8 +812,8 @@ Creates new check constraint.
|
||||
dropCheckConstraint(table: Table|string, checkOrName: TableCheck|string): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `checkOrName` - TableCheck object or check constraint name
|
||||
- `table` - Table object or name
|
||||
- `checkOrName` - TableCheck object or check constraint name
|
||||
|
||||
Drops check constraint.
|
||||
|
||||
@ -810,8 +825,8 @@ Drops check constraint.
|
||||
dropCheckConstraints(table: Table|string, checkConstraints: TableCheck[]): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `checkConstraints` - array of TableCheck objects
|
||||
- `table` - Table object or name
|
||||
- `checkConstraints` - array of TableCheck objects
|
||||
|
||||
Drops check constraints.
|
||||
|
||||
@ -823,8 +838,8 @@ Drops check constraints.
|
||||
createForeignKey(table: Table|string, foreignKey: TableForeignKey): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `foreignKey` - TableForeignKey object
|
||||
- `table` - Table object or name
|
||||
- `foreignKey` - TableForeignKey object
|
||||
|
||||
Creates a new foreign key.
|
||||
|
||||
@ -834,8 +849,8 @@ Creates a new foreign key.
|
||||
createForeignKeys(table: Table|string, foreignKeys: TableForeignKey[]): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `foreignKeys` - array of TableForeignKey objects
|
||||
- `table` - Table object or name
|
||||
- `foreignKeys` - array of TableForeignKey objects
|
||||
|
||||
Creates a new foreign keys.
|
||||
|
||||
@ -845,8 +860,8 @@ Creates a new foreign keys.
|
||||
dropForeignKey(table: Table|string, foreignKeyOrName: TableForeignKey|string): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `foreignKeyOrName` - TableForeignKey object or foreign key name
|
||||
- `table` - Table object or name
|
||||
- `foreignKeyOrName` - TableForeignKey object or foreign key name
|
||||
|
||||
Drops a foreign key.
|
||||
|
||||
@ -856,8 +871,8 @@ Drops a foreign key.
|
||||
dropForeignKeys(table: Table|string, foreignKeys: TableForeignKey[]): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `foreignKeys` - array of TableForeignKey objects
|
||||
- `table` - Table object or name
|
||||
- `foreignKeys` - array of TableForeignKey objects
|
||||
|
||||
Drops a foreign keys.
|
||||
|
||||
@ -867,8 +882,8 @@ Drops a foreign keys.
|
||||
createIndex(table: Table|string, index: TableIndex): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `index` - TableIndex object
|
||||
- `table` - Table object or name
|
||||
- `index` - TableIndex object
|
||||
|
||||
Creates a new index.
|
||||
|
||||
@ -878,8 +893,8 @@ Creates a new index.
|
||||
createIndices(table: Table|string, indices: TableIndex[]): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `indices` - array of TableIndex objects
|
||||
- `table` - Table object or name
|
||||
- `indices` - array of TableIndex objects
|
||||
|
||||
Creates a new indices.
|
||||
|
||||
@ -889,8 +904,8 @@ Creates a new indices.
|
||||
dropIndex(table: Table|string, index: TableIndex|string): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `index` - TableIndex object or index name
|
||||
- `table` - Table object or name
|
||||
- `index` - TableIndex object or index name
|
||||
|
||||
Drops an index.
|
||||
|
||||
@ -900,8 +915,8 @@ Drops an index.
|
||||
dropIndices(table: Table|string, indices: TableIndex[]): Promise<void>
|
||||
```
|
||||
|
||||
- `table` - Table object or name
|
||||
- `indices` - array of TableIndex objects
|
||||
- `table` - Table object or name
|
||||
- `indices` - array of TableIndex objects
|
||||
|
||||
Drops an indices.
|
||||
|
||||
@ -911,7 +926,7 @@ Drops an indices.
|
||||
clearTable(tableName: string): Promise<void>
|
||||
```
|
||||
|
||||
- `tableName` - table name
|
||||
- `tableName` - table name
|
||||
|
||||
Clears all table contents.
|
||||
|
||||
@ -948,7 +963,7 @@ Flushes all memorized sql statements.
|
||||
getMemorySql(): SqlInMemory
|
||||
```
|
||||
|
||||
- returns `SqlInMemory` object with array of `upQueries` and `downQueries` sql statements
|
||||
- returns `SqlInMemory` object with array of `upQueries` and `downQueries` sql statements
|
||||
|
||||
Gets sql stored in the memory. Parameters in the sql are already replaced.
|
||||
|
||||
@ -1,9 +1,5 @@
|
||||
# Transactions
|
||||
|
||||
- [Creating and using transactions](#creating-and-using-transactions)
|
||||
- [Specifying Isolation Levels](#specifying-isolation-levels)
|
||||
- [Using `QueryRunner` to create and control state of single database connection](#using-queryrunner-to-create-and-control-state-of-single-database-connection)
|
||||
|
||||
## Creating and using transactions
|
||||
|
||||
Transactions are created using `DataSource` or `EntityManager`.
|
||||
@ -107,4 +103,4 @@ There are 3 methods to control transactions in `QueryRunner`:
|
||||
- `commitTransaction` - commits all changes made using the query runner instance.
|
||||
- `rollbackTransaction` - rolls all changes made using the query runner instance back.
|
||||
|
||||
Learn more about [Query Runner](./query-runner.md).
|
||||
Learn more about [Query Runner](../query-runner.md).
|
||||
@ -1,11 +1,5 @@
|
||||
# Indices
|
||||
|
||||
- [Column indices](#column-indices)
|
||||
- [Unique indices](#unique-indices)
|
||||
- [Indices with multiple columns](#indices-with-multiple-columns)
|
||||
- [Spatial Indices](#spatial-indices)
|
||||
- [Disabling synchronization](#disabling-synchronization)
|
||||
|
||||
## Column indices
|
||||
|
||||
You can create a database index for a specific column by using `@Index` on a column you want to make an index.
|
||||
@ -148,7 +142,7 @@ Typeorm supports generating SQL with this option if when the concurrent option i
|
||||
@Index(["firstName", "middleName", "lastName"], { concurrent: true })
|
||||
```
|
||||
|
||||
For more information see the [postgres documentation](https://www.postgresql.org/docs/current/sql-createindex.html).
|
||||
For more information see the [Postgres documentation](https://www.postgresql.org/docs/current/sql-createindex.html).
|
||||
|
||||
## Disabling synchronization
|
||||
|
||||
@ -1,22 +1,6 @@
|
||||
# Entity Listeners and Subscribers
|
||||
|
||||
- [Entity Listeners and Subscribers](#entity-listeners-and-subscribers)
|
||||
- [What is an Entity Listener](#what-is-an-entity-listener)
|
||||
- [`@AfterLoad`](#afterload)
|
||||
- [`@BeforeInsert`](#beforeinsert)
|
||||
- [`@AfterInsert`](#afterinsert)
|
||||
- [`@BeforeUpdate`](#beforeupdate)
|
||||
- [`@AfterUpdate`](#afterupdate)
|
||||
- [`@BeforeRemove`](#beforeremove)
|
||||
- [`@AfterRemove`](#afterremove)
|
||||
- [`@BeforeSoftRemove`](#beforesoftremove)
|
||||
- [`@AfterSoftRemove`](#aftersoftremove)
|
||||
- [`@BeforeRecover`](#beforerecover)
|
||||
- [`@AfterRecover`](#afterrecover)
|
||||
- [What is a Subscriber](#what-is-a-subscriber)
|
||||
- [`Event Object`](#event-object)
|
||||
|
||||
## What is an Entity Listener
|
||||
## What is an Entity Listener?
|
||||
|
||||
Any of your entities can have methods with custom logic that listen to specific entity events.
|
||||
You must mark those methods with special decorators depending on what event you want to listen to.
|
||||
@ -200,7 +184,7 @@ export class Post {
|
||||
}
|
||||
```
|
||||
|
||||
## What is a Subscriber
|
||||
## What is a Subscriber?
|
||||
|
||||
Marks a class as an event subscriber which can listen to specific entity events or any entity events.
|
||||
Events are firing using `QueryBuilder` and repository/manager methods.
|
||||
@ -384,7 +368,7 @@ export class PostSubscriber implements EntitySubscriberInterface {
|
||||
}
|
||||
```
|
||||
|
||||
Make sure your `subscribers` property is set in your [DataSourceOptions](./data-source-options.md#common-data-source-options) so TypeORM loads your subscriber.
|
||||
Make sure your `subscribers` property is set in your [DataSourceOptions](../data-source/2-data-source-options.md#common-data-source-options) so TypeORM loads your subscriber.
|
||||
|
||||
### `Event Object`
|
||||
|
||||
@ -1,11 +1,5 @@
|
||||
# Logging
|
||||
|
||||
- [Enabling logging](#enabling-logging)
|
||||
- [Logging options](#logging-options)
|
||||
- [Log long-running queries](#log-long-running-queries)
|
||||
- [Changing default logger](#changing-default-logger)
|
||||
- [Using custom logger](#using-custom-logger)
|
||||
|
||||
## Enabling logging
|
||||
|
||||
You can enable logging of all queries and errors by simply setting `logging: true` in data source options:
|
||||
@ -1,21 +1,5 @@
|
||||
# Using CLI
|
||||
|
||||
- [Installing CLI](#installing-cli)
|
||||
- [Initialize a new TypeORM project](#initialize-a-new-typeorm-project)
|
||||
- [Create a new entity](#create-a-new-entity)
|
||||
- [Create a new subscriber](#create-a-new-subscriber)
|
||||
- [Create a new migration](#create-a-new-migration)
|
||||
- [Generate a migration from existing table schema](#generate-a-migration-from-existing-table-schema)
|
||||
- [Run migrations](#run-migrations)
|
||||
- [Revert migrations](#revert-migrations)
|
||||
- [Show migrations](#show-migrations)
|
||||
- [Sync database schema](#sync-database-schema)
|
||||
- [Log sync database schema queries without actual running them](#log-sync-database-schema-queries-without-actual-running-them)
|
||||
- [Drop database schema](#drop-database-schema)
|
||||
- [Run any SQL query](#run-any-sql-query)
|
||||
- [Clear cache](#clear-cache)
|
||||
- [Check version](#check-version)
|
||||
|
||||
## Installing CLI
|
||||
|
||||
### If entities files are in javascript
|
||||
@ -63,7 +47,7 @@ Then you may run the command like this:
|
||||
npm run typeorm migration:run -- -d path-to-datasource-config
|
||||
```
|
||||
|
||||
### How to read the documentation
|
||||
### How to read the documentation?
|
||||
|
||||
To reduce verbosity of the documentation, the following sections are using a globally installed typeorm CLI. Depending on how you installed the CLI, you may replace `typeorm` at the start of the command, by either `npx typeorm` or `npm run typeorm`.
|
||||
|
||||
@ -128,7 +112,7 @@ You can create a new entity using CLI:
|
||||
typeorm entity:create path-to-entity-dir/entity
|
||||
```
|
||||
|
||||
Learn more about [entities](./entities.md).
|
||||
Learn more about [entities](../entity/1-entities.md).
|
||||
|
||||
## Create a new subscriber
|
||||
|
||||
@ -138,7 +122,7 @@ You can create a new subscriber using CLI:
|
||||
typeorm subscriber:create path-to-subscriber-dir/subscriber
|
||||
```
|
||||
|
||||
Learn more about [Subscribers](./listeners-and-subscribers.md).
|
||||
Learn more about [Subscribers](./4-listeners-and-subscribers.md).
|
||||
|
||||
## Create a new migration
|
||||
|
||||
@ -147,7 +131,8 @@ You can create a new migration using CLI:
|
||||
```
|
||||
typeorm migration:create path-to-migrations-dir/migrationName
|
||||
```
|
||||
Learn more about [Migrations](./migrations.md).
|
||||
|
||||
Learn more about [Migrations](./1-migrations.md).
|
||||
|
||||
## Generate a migration from existing table schema
|
||||
|
||||
@ -164,7 +149,7 @@ The rule of thumb is to generate a migration after each entity change.
|
||||
the -d argument value should specify the path where your DataSource instance is defined.
|
||||
You can specify the path and name of the migration with the first argument.
|
||||
|
||||
Learn more about [Migrations](./migrations.md).
|
||||
Learn more about [Migrations](./1-migrations.md).
|
||||
|
||||
## Run migrations
|
||||
|
||||
@ -174,7 +159,7 @@ To execute all pending migrations use following command:
|
||||
typeorm migration:run -- -d path-to-datasource-config
|
||||
```
|
||||
|
||||
Learn more about [Migrations](./migrations.md).
|
||||
Learn more about [Migrations](./1-migrations.md).
|
||||
|
||||
## Revert migrations
|
||||
|
||||
@ -186,7 +171,7 @@ typeorm migration:revert -- -d path-to-datasource-config
|
||||
|
||||
This command will undo only the last executed migration.
|
||||
You can execute this command multiple times to revert multiple migrations.
|
||||
Learn more about [Migrations](./migrations.md).
|
||||
Learn more about [Migrations](./1-migrations.md).
|
||||
|
||||
## Show migrations
|
||||
|
||||
207
docs/docs/advanced-topics/7-performance-optimizing.md
Normal file
@ -0,0 +1,207 @@
|
||||
# Performance and optimization in TypeORM
|
||||
|
||||
## 1. Introduction to performance optimization
|
||||
|
||||
- In applications using ORM like TypeORM, performance optimization is crucial to ensure the system runs smoothly, minimizes latency, and uses resources efficiently.
|
||||
|
||||
- Common challenges when using ORM include unnecessary data retrieval, N+1 query problems, and not leveraging optimization tools such as indexing or caching.
|
||||
|
||||
- The main goals of optimization include:
|
||||
|
||||
- Reducing the number of SQL queries sent to the database.
|
||||
- Optimizing complex queries to run faster.
|
||||
- Using caching and indexing to speed up data retrieval.
|
||||
- Ensuring efficient data retrieval using appropriate loading methods (Lazy vs. Eager loading).
|
||||
|
||||
## 2. Efficient use of Query Builder
|
||||
|
||||
### 2.1. Avoiding the N+1 Query Problem
|
||||
|
||||
- The N+1 Query Problem occurs when the system executes too many sub-queries for each row of data retrieved.
|
||||
|
||||
- To avoid this, you can use `leftJoinAndSelect` or `innerJoinAndSelect` to combine tables in a single query instead of executing multiple queries.
|
||||
|
||||
```typescript
|
||||
const users = await dataSource
|
||||
.getRepository(User)
|
||||
.createQueryBuilder("user")
|
||||
.leftJoinAndSelect("user.posts", "post")
|
||||
.getMany()
|
||||
```
|
||||
|
||||
- Here, `leftJoinAndSelect` helps retrieve all user posts in a single query rather than many small queries.
|
||||
|
||||
### 2.2. Use `getRawMany()` when only raw data is needed
|
||||
|
||||
- In cases where full objects aren't required, you can use `getRawMany()` to fetch raw data and avoid TypeORM processing too much information.
|
||||
|
||||
```typescript
|
||||
const rawPosts = await dataSource
|
||||
.getRepository(Post)
|
||||
.createQueryBuilder("post")
|
||||
.select("post.title, post.createdAt")
|
||||
.getRawMany()
|
||||
```
|
||||
|
||||
### 2.3. Limit fields using `select`
|
||||
|
||||
- To optimize memory usage and reduce unnecessary data, select only the required fields using `select`.
|
||||
|
||||
```typescript
|
||||
const users = await dataSource
|
||||
.getRepository(User)
|
||||
.createQueryBuilder("user")
|
||||
.select(["user.name", "user.email"])
|
||||
.getMany()
|
||||
```
|
||||
|
||||
## 3. Using indices
|
||||
|
||||
- Indexes speed up query performance in the database by reducing the amount of data scanned. TypeORM supports creating indexes on table columns using the `@Index` decorator.
|
||||
|
||||
### 3.1. Creating an index
|
||||
|
||||
- Indexes can be created directly in entities using the `@Index` decorator.
|
||||
|
||||
```typescript
|
||||
import { Entity, Column, Index } from "typeorm"
|
||||
|
||||
@Entity()
|
||||
@Index(["firstName", "lastName"]) // Composite index
|
||||
export class User {
|
||||
@Column()
|
||||
firstName: string
|
||||
|
||||
@Column()
|
||||
lastName: string
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2. Unique index
|
||||
|
||||
- You can create unique indexes to ensure no duplicate values in a column.
|
||||
|
||||
```typescript
|
||||
@Index(["email"], { unique: true })
|
||||
```
|
||||
|
||||
## 4. Lazy loading and Eager Loading
|
||||
|
||||
TypeORM provides two main methods for loading data relations: Lazy Loading and Eager Loading. Each has a different impact on the performance of your application.
|
||||
|
||||
### 4.1. Lazy loading
|
||||
|
||||
- Lazy loading loads the relation data only when needed, reducing database load when all related data isn't always necessary.
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class User {
|
||||
@OneToMany(() => Post, (post) => post.user, { lazy: true })
|
||||
posts: Promise<Post[]>
|
||||
}
|
||||
```
|
||||
|
||||
- When you need to retrieve the data, simply call
|
||||
|
||||
```typescript
|
||||
const user = await userRepository.findOne(userId)
|
||||
const posts = await user.posts
|
||||
```
|
||||
|
||||
- Advantages:
|
||||
- Resource efficiency: Only loads the necessary data when actually required, reducing query costs and memory usage.
|
||||
- Ideal for selective data usage: Suitable for scenarios where not all related data is needed.
|
||||
- Disadvantages:
|
||||
- Increased query complexity: Each access to related data triggers an additional query to the database, which may increase latency if not managed properly.
|
||||
- Difficult to track: Can lead to the n+1 query problem if used carelessly.
|
||||
|
||||
### 4.2. Eager Loading
|
||||
|
||||
- Eager loading automatically retrieves all related data when the main query is executed. This can be convenient but may cause performance issues if there are too many complex relations.
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class User {
|
||||
@OneToMany(() => Post, (post) => post.user, { eager: true })
|
||||
posts: Post[]
|
||||
}
|
||||
```
|
||||
|
||||
- In this case, posts will be loaded as soon as user data is retrieved.
|
||||
|
||||
- Advantages:
|
||||
- Automatically loads related data, making it easier to access relationships without additional queries.
|
||||
- Avoids the n+1 query problem: Since all data is fetched in a single query, there's no risk of generating unnecessary multiple queries.
|
||||
- Disadvantages:
|
||||
|
||||
- Fetching all related data at once may result in large queries, even if not all data is needed.
|
||||
- Not suitable for scenarios where only a subset of related data is required, as it can lead to inefficient data usage.
|
||||
|
||||
- To explore more details and examples of how to configure and use lazy and eager relations, visit the official TypeORM documentation: [Eager and Lazy Relations](../relations/5-eager-and-lazy-relations.md)
|
||||
|
||||
## 5. Advanced optimization
|
||||
|
||||
### 5.1. Using Query Hints
|
||||
|
||||
- Query Hints are instructions sent along with SQL queries, helping the database decide on more efficient execution strategies.
|
||||
|
||||
- Different RDBMS systems support different kinds of hints, such as suggesting index usage or choosing the appropriate JOIN type.
|
||||
|
||||
```typescript
|
||||
await dataSource.query(`
|
||||
SELECT /*+ MAX_EXECUTION_TIME(1000) */ *
|
||||
FROM user
|
||||
WHERE email = 'example@example.com'
|
||||
`)
|
||||
```
|
||||
|
||||
- In the example above, `MAX_EXECUTION_TIME(1000)` instructs MySQL to stop the query if it takes more than 1 second.
|
||||
|
||||
### 5.2. Pagination
|
||||
|
||||
- Pagination is a crucial technique for improving performance when retrieving large amounts of data. Instead of fetching all data at once, pagination divides data into smaller pages, reducing database load and optimizing memory usage.
|
||||
|
||||
- In TypeORM, you can use `limit` and `offset` for pagination.
|
||||
|
||||
```typescript
|
||||
const users = await userRepository
|
||||
.createQueryBuilder("user")
|
||||
.limit(10) // Number of records to fetch per page
|
||||
.offset(20) // Skip the first 20 records
|
||||
.getMany()
|
||||
```
|
||||
|
||||
- Pagination helps prevent fetching large amounts of data at once, minimizing latency and optimizing memory usage. When implementing pagination, consider using pagination cursors for more efficient handling of dynamic data.
|
||||
|
||||
### 5.3. Caching
|
||||
|
||||
- Caching is the technique of temporarily storing query results or data for use in future requests without querying the database each time.
|
||||
|
||||
- TypeORM has built-in caching support, and you can customize how caching is used.
|
||||
|
||||
```typescript
|
||||
const users = await userRepository
|
||||
.createQueryBuilder("user")
|
||||
.cache(true) // Enable caching
|
||||
.getMany()
|
||||
```
|
||||
|
||||
- Additionally, you can configure cache duration or use external caching tools like Redis for better efficiency.
|
||||
|
||||
```typescript=
|
||||
const dataSource = new DataSource({
|
||||
type: "mysql",
|
||||
host: "localhost",
|
||||
port: 3306,
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test",
|
||||
cache: {
|
||||
type: "redis",
|
||||
options: {
|
||||
host: "localhost",
|
||||
port: 6379
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
@ -1,10 +1,6 @@
|
||||
# Working with DataSource
|
||||
# DataSource
|
||||
|
||||
- [What is `DataSource`](#what-is-datasource)
|
||||
- [Creating a new DataSource](#creating-a-new-datasource)
|
||||
- [How to use DataSource](#how-to-use-datasource)
|
||||
|
||||
## What is `DataSource`
|
||||
## What is a DataSource?
|
||||
|
||||
Your interaction with the database is only possible once you setup a `DataSource`.
|
||||
TypeORM's `DataSource` holds your database connection settings and
|
||||
@ -80,7 +76,7 @@ const PostgresDataSource = new DataSource({
|
||||
})
|
||||
```
|
||||
|
||||
## How to use DataSource
|
||||
## How to use DataSource?
|
||||
|
||||
Once you set your `DataSource`, you can use it anywhere in your app, for example:
|
||||
|
||||
@ -98,4 +94,4 @@ export class UserController {
|
||||
|
||||
Using the `DataSource` instance you can execute database operations with your entities,
|
||||
particularly using `.manager` and `.getRepository()` properties.
|
||||
For more information about them see [Entity Manager and Repository](working-with-entity-manager.md) documentation.
|
||||
For more information about them see [Entity Manager](../working-with-entity-manager/1-working-with-entity-manager.md) and [Repository](../working-with-entity-manager/2-working-with-repository.md) documentation.
|
||||
@ -1,23 +1,6 @@
|
||||
# Data Source Options
|
||||
|
||||
- [What is `DataSourceOptions`](#what-is-datasourceoptions)
|
||||
- [Common data source options](#common-data-source-options)
|
||||
- [`mysql` / `mariadb` data source options](#mysql--mariadb-data-source-options)
|
||||
- [`postgres` / `cockroachdb` data source options](#postgres--cockroachdb-data-source-options)
|
||||
- [`sqlite` data source options](#sqlite-data-source-options)
|
||||
- [`better-sqlite3` data source options](#better-sqlite3-data-source-options)
|
||||
- [`capacitor` data source options](#capacitor-data-source-options)
|
||||
- [`cordova` data source options](#cordova-data-source-options)
|
||||
- [`react-native` data source options](#react-native-data-source-options)
|
||||
- [`nativescript` data source options](#nativescript-data-source-options)
|
||||
- [`mssql` data source options](#mssql-data-source-options)
|
||||
- [`mongodb` data source options](#mongodb-data-source-options)
|
||||
- [`sql.js` data source options](#sqljs-data-source-options)
|
||||
- [`expo` data source options](#expo-data-source-options)
|
||||
- [`oracle` data source options](#oracle-data-source-options)
|
||||
- [DataSource options example](#data-source-options-example)
|
||||
|
||||
## What is `DataSourceOptions`
|
||||
## What is DataSourceOptions?
|
||||
|
||||
`DataSourceOptions` is a data source configuration you pass when you create a new `DataSource` instance.
|
||||
Different RDBMS-es have their own specific options.
|
||||
@ -36,29 +19,29 @@ Different RDBMS-es have their own specific options.
|
||||
It accepts entity classes, entity schema classes, and directory paths from which to load.
|
||||
Directories support glob patterns.
|
||||
Example: `entities: [Post, Category, "entity/*.js", "modules/**/entity/*.js"]`.
|
||||
Learn more about [Entities](entities.md).
|
||||
Learn more about [Entity Schemas](separating-entity-definition.md).
|
||||
Learn more about [Entities](../entity/1-entities.md).
|
||||
Learn more about [Entity Schemas](../entity/6-separating-entity-definition.md).
|
||||
|
||||
- `subscribers` - Subscribers to be loaded and used for this data source.
|
||||
It accepts both entity classes and directories from which to load.
|
||||
Directories support glob patterns.
|
||||
Example: `subscribers: [PostSubscriber, AppSubscriber, "subscriber/*.js", "modules/**/subscriber/*.js"]`.
|
||||
Learn more about [Subscribers](listeners-and-subscribers.md).
|
||||
Learn more about [Subscribers](../advanced-topics/4-listeners-and-subscribers.md).
|
||||
|
||||
- `migrations` - Migrations to be loaded and used for this data source.
|
||||
It accepts both migration classes and directories from which to load.
|
||||
Directories support glob patterns.
|
||||
Example: `migrations: [FirstMigration, SecondMigration, "migration/*.js", "modules/**/migration/*.js"]`.
|
||||
Learn more about [Migrations](migrations.md).
|
||||
Learn more about [Migrations](../advanced-topics/1-migrations.md).
|
||||
|
||||
- `logging` - Indicates if logging is enabled or not.
|
||||
If set to `true` then query and error logging will be enabled.
|
||||
You can also specify different types of logging to be enabled, for example `["query", "error", "schema"]`.
|
||||
Learn more about [Logging](logging.md).
|
||||
Learn more about [Logging](../advanced-topics/5-logging.md).
|
||||
|
||||
- `logger` - Logger to be used for logging purposes. Possible values are "advanced-console", "formatted-console", "simple-console" and "file".
|
||||
Default is "advanced-console". You can also specify a logger class that implements `Logger` interface.
|
||||
Learn more about [Logging](logging.md).
|
||||
Learn more about [Logging](../advanced-topics/5-logging.md).
|
||||
|
||||
- `maxQueryExecutionTime` - If query execution time exceed this given max execution time (in milliseconds)
|
||||
then logger will log this query.
|
||||
@ -96,7 +79,7 @@ Different RDBMS-es have their own specific options.
|
||||
By default, this table is called "typeorm_metadata".
|
||||
|
||||
- `cache` - Enables entity result caching. You can also configure cache type and other cache options here.
|
||||
Read more about caching [here](caching.md).
|
||||
Read more about caching [here](../query-builder/6-caching.md).
|
||||
|
||||
- `isolateWhereStatements` - Enables where statement isolation, wrapping each where clause in brackets automatically.
|
||||
eg. `.where("user.firstName = :search OR user.lastName = :search")` becomes `WHERE (user.firstName = ? OR user.lastName = ?)` instead of `WHERE user.firstName = ? OR user.lastName = ?`
|
||||
@ -248,7 +231,7 @@ Different RDBMS-es have their own specific options.
|
||||
|
||||
## `mssql` data source options
|
||||
|
||||
Based on [tedious](https://tediousjs.github.io/node-mssql/) MSSQL implementation. See [SqlServerConnectionOptions.ts](..\src\driver\sqlserver\SqlServerConnectionOptions.ts) for details on exposed attributes.
|
||||
Based on [tedious](https://tediousjs.github.io/node-mssql/) MSSQL implementation. See [SqlServerConnectionOptions.ts](https://github.com/typeorm/typeorm/tree/master/src/driver/sqlserver/SqlServerConnectionOptions.ts) for details on exposed attributes.
|
||||
|
||||
- `url` - Connection url where the connection is performed. Please note that other data source options will override parameters set from url.
|
||||
|
||||
@ -1,10 +1,5 @@
|
||||
# Multiple data sources, databases, schemas and replication setup
|
||||
|
||||
- [Using multiple data sources](#using-multiple-data-sources)
|
||||
- [Using multiple databases in a single data source](#using-multiple-databases-within-a-single-data-source)
|
||||
- [Using multiple schemas in a single data source](#using-multiple-schemas-within-a-single-data-source)
|
||||
- [Replication](#replication)
|
||||
|
||||
## Using multiple data sources
|
||||
|
||||
To use multiple data sources connected to different databases, simply create multiple DataSource instances:
|
||||
@ -198,45 +193,46 @@ Example of replication options:
|
||||
|
||||
```typescript
|
||||
const datasource = new DataSource({
|
||||
type: "mysql",
|
||||
logging: true,
|
||||
replication: {
|
||||
master: {
|
||||
host: "server1",
|
||||
port: 3306,
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test"
|
||||
type: "mysql",
|
||||
logging: true,
|
||||
replication: {
|
||||
master: {
|
||||
host: "server1",
|
||||
port: 3306,
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test",
|
||||
},
|
||||
slaves: [
|
||||
{
|
||||
host: "server2",
|
||||
port: 3306,
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test",
|
||||
},
|
||||
{
|
||||
host: "server3",
|
||||
port: 3306,
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test",
|
||||
},
|
||||
],
|
||||
},
|
||||
slaves: [
|
||||
{
|
||||
host: "server2",
|
||||
port: 3306,
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test"
|
||||
}, {
|
||||
host: "server3",
|
||||
port: 3306,
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test"
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
With replication slaves defined, TypeORM will start sending all possible queries to slaves by default.
|
||||
|
||||
- all queries performed by the `find` methods or `SelectQueryBuilder` will use a random `slave` instance
|
||||
- all write queries performed by `update`, `create`, `InsertQueryBuilder`, `UpdateQueryBuilder`, etc will use the `master` instance
|
||||
- all raw queries performed by calling `.query()` will use the `master` instance
|
||||
- all schema update operations are performed using the `master` instance
|
||||
- all queries performed by the `find` methods or `SelectQueryBuilder` will use a random `slave` instance
|
||||
- all write queries performed by `update`, `create`, `InsertQueryBuilder`, `UpdateQueryBuilder`, etc will use the `master` instance
|
||||
- all raw queries performed by calling `.query()` will use the `master` instance
|
||||
- all schema update operations are performed using the `master` instance
|
||||
|
||||
### Explicitly selecting query destinations
|
||||
|
||||
By default, TypeORM will send all read queries to a random read slave, and all writes to the master. This means when you first add the `replication` settings to your configuration, any existing read query runners that don't explicitly specify a replication mode will start going to a slave. This is good for scalability, but if some of those queries *must* return up to date data, then you need to explicitly pass a replication mode when you create a query runner.
|
||||
By default, TypeORM will send all read queries to a random read slave, and all writes to the master. This means when you first add the `replication` settings to your configuration, any existing read query runners that don't explicitly specify a replication mode will start going to a slave. This is good for scalability, but if some of those queries _must_ return up to date data, then you need to explicitly pass a replication mode when you create a query runner.
|
||||
|
||||
If you want to explicitly use the `master` for read queries, pass an explicit `ReplicationMode` when creating your `QueryRunner`;
|
||||
|
||||
@ -275,29 +271,29 @@ If you don't want all reads to go to a `slave` instance by default, you can chan
|
||||
|
||||
```typescript
|
||||
const datasource = new DataSource({
|
||||
type: "mysql",
|
||||
logging: true,
|
||||
replication: {
|
||||
// set the default destination for read queries as the master instance
|
||||
defaultMode: "master",
|
||||
master: {
|
||||
host: "server1",
|
||||
port: 3306,
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test"
|
||||
type: "mysql",
|
||||
logging: true,
|
||||
replication: {
|
||||
// set the default destination for read queries as the master instance
|
||||
defaultMode: "master",
|
||||
master: {
|
||||
host: "server1",
|
||||
port: 3306,
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test",
|
||||
},
|
||||
slaves: [
|
||||
{
|
||||
host: "server2",
|
||||
port: 3306,
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test",
|
||||
},
|
||||
],
|
||||
},
|
||||
slaves: [
|
||||
{
|
||||
host: "server2",
|
||||
port: 3306,
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test"
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
With this mode, no queries will go to the read slaves by default, and you'll have to opt-in to sending queries to read slaves with explicit `.createQueryRunner("slave")` calls.
|
||||
@ -1,7 +1,7 @@
|
||||
# DataSource API
|
||||
|
||||
- `options` - Options used to create this dataSource.
|
||||
Learn more about [DataSourceOptions](data-source-options.md).
|
||||
Learn more about [DataSourceOptions](./2-data-source-options.md).
|
||||
|
||||
```typescript
|
||||
const dataSourceOptions: DataSourceOptions = dataSource.options
|
||||
@ -20,7 +20,7 @@ const driver: Driver = dataSource.driver
|
||||
```
|
||||
|
||||
- `manager` - `EntityManager` used to work with entities.
|
||||
Learn more about [Entity Manager and Repository](working-with-entity-manager.md).
|
||||
Learn more about [Entity Manager](../working-with-entity-manager/1-working-with-entity-manager.md) and [Repository](../working-with-entity-manager/2-working-with-repository.md).
|
||||
|
||||
```typescript
|
||||
const manager: EntityManager = dataSource.manager
|
||||
@ -29,7 +29,7 @@ const users = await manager.find()
|
||||
```
|
||||
|
||||
- `mongoManager` - `MongoEntityManager` used to work with entities for mongodb data source.
|
||||
For more information about MongoEntityManager see [MongoDB](mongodb.md) documentation.
|
||||
For more information about MongoEntityManager see [MongoDB](../guides/2-mongodb.md) documentation.
|
||||
|
||||
```typescript
|
||||
const manager: MongoEntityManager = dataSource.mongoManager
|
||||
@ -78,7 +78,6 @@ await dataSource.undoLastMigration()
|
||||
```
|
||||
|
||||
- `hasMetadata` - Checks if metadata for a given entity is registered.
|
||||
Learn more about [Entity Metadata](entity-metadata.md).
|
||||
|
||||
```typescript
|
||||
if (dataSource.hasMetadata(User))
|
||||
@ -87,7 +86,6 @@ if (dataSource.hasMetadata(User))
|
||||
|
||||
- `getMetadata` - Gets `EntityMetadata` of the given entity.
|
||||
You can also specify a table name and if entity metadata with such table name is found it will be returned.
|
||||
Learn more about [Entity Metadata](entity-metadata.md).
|
||||
|
||||
```typescript
|
||||
const userMetadata = dataSource.getMetadata(User)
|
||||
@ -96,7 +94,7 @@ const userMetadata = dataSource.getMetadata(User)
|
||||
|
||||
- `getRepository` - Gets `Repository` of the given entity.
|
||||
You can also specify a table name and if repository for given table is found it will be returned.
|
||||
Learn more about [Repositories](working-with-repository.md).
|
||||
Learn more about [Repositories](../working-with-entity-manager/2-working-with-repository.md).
|
||||
|
||||
```typescript
|
||||
const repository = dataSource.getRepository(User)
|
||||
@ -106,7 +104,7 @@ const users = await repository.find()
|
||||
|
||||
- `getTreeRepository` - Gets `TreeRepository` of the given entity.
|
||||
You can also specify a table name and if repository for given table is found it will be returned.
|
||||
Learn more about [Repositories](working-with-repository.md).
|
||||
Learn more about [Repositories](../working-with-entity-manager/2-working-with-repository.md).
|
||||
|
||||
```typescript
|
||||
const repository = dataSource.getTreeRepository(Category)
|
||||
@ -116,7 +114,7 @@ const categories = await repository.findTrees()
|
||||
|
||||
- `getMongoRepository` - Gets `MongoRepository` of the given entity.
|
||||
This repository is used for entities in MongoDB dataSource.
|
||||
Learn more about [MongoDB support](mongodb.md).
|
||||
Learn more about [MongoDB support](../guides/2-mongodb.md).
|
||||
|
||||
```typescript
|
||||
const repository = dataSource.getMongoRepository(User)
|
||||
@ -127,7 +125,7 @@ const category2 = await categoryCursor.next()
|
||||
```
|
||||
|
||||
- `transaction` - Provides a single transaction where multiple database requests will be executed in a single database transaction.
|
||||
Learn more about [Transactions](transactions.md).
|
||||
Learn more about [Transactions](../advanced-topics/2-transactions.md).
|
||||
|
||||
```typescript
|
||||
await dataSource.transaction(async (manager) => {
|
||||
@ -149,32 +147,32 @@ const rawData = await dataSource.query(`SELECT * FROM USERS`)
|
||||
// expo, mariadb, mysql, nativescript, react-native,
|
||||
// sap, sqlite, sqljs
|
||||
const rawData = await dataSource.query(
|
||||
'SELECT * FROM USERS WHERE name = ? and age = ?',
|
||||
[ 'John', 24 ]
|
||||
"SELECT * FROM USERS WHERE name = ? and age = ?",
|
||||
["John", 24],
|
||||
)
|
||||
|
||||
// aurora-postgres, cockroachdb, postgres
|
||||
const rawData = await dataSource.query(
|
||||
'SELECT * FROM USERS WHERE name = $1 and age = $2',
|
||||
['John', 24]
|
||||
"SELECT * FROM USERS WHERE name = $1 and age = $2",
|
||||
["John", 24],
|
||||
)
|
||||
|
||||
// oracle
|
||||
const rawData = await dataSource.query(
|
||||
'SELECT * FROM USERS WHERE name = :1 and age = :2',
|
||||
['John', 24]
|
||||
"SELECT * FROM USERS WHERE name = :1 and age = :2",
|
||||
["John", 24],
|
||||
)
|
||||
|
||||
// spanner
|
||||
const rawData = await dataSource.query(
|
||||
'SELECT * FROM USERS WHERE name = @param0 and age = @param1',
|
||||
[ 'John', 24 ]
|
||||
"SELECT * FROM USERS WHERE name = @param0 and age = @param1",
|
||||
["John", 24],
|
||||
)
|
||||
|
||||
// mssql
|
||||
const rawData = await dataSource.query(
|
||||
'SELECT * FROM USERS WHERE name = @0 and age = @1',
|
||||
[ 'John', 24 ]
|
||||
"SELECT * FROM USERS WHERE name = @0 and age = @1",
|
||||
["John", 24],
|
||||
)
|
||||
```
|
||||
|
||||
@ -187,7 +185,7 @@ const rawData = await dataSource.sql`SELECT * FROM USERS WHERE name = ${'John'}
|
||||
Learn more about using the [SQL Tag syntax](sql-tag.md).
|
||||
|
||||
- `createQueryBuilder` - Creates a query builder, which can be used to build queries.
|
||||
Learn more about [QueryBuilder](select-query-builder.md).
|
||||
Learn more about [QueryBuilder](../query-builder/1-select-query-builder.md).
|
||||
|
||||
```typescript
|
||||
const users = await dataSource
|
||||
@ -199,7 +197,7 @@ const users = await dataSource
|
||||
```
|
||||
|
||||
- `createQueryRunner` - Creates a query runner used to manage and work with a single real database dataSource.
|
||||
Learn more about [QueryRunner](query-runner.md).
|
||||
Learn more about [QueryRunner](../query-runner.md).
|
||||
|
||||
```typescript
|
||||
const queryRunner = dataSource.createQueryRunner()
|
||||
@ -1,32 +1,6 @@
|
||||
# Entities
|
||||
|
||||
- [Entities](#entities)
|
||||
- [What is Entity?](#what-is-entity)
|
||||
- [Entity columns](#entity-columns)
|
||||
- [Primary columns](#primary-columns)
|
||||
- [Special columns](#special-columns)
|
||||
- [Spatial columns](#spatial-columns)
|
||||
- [Column types](#column-types)
|
||||
- [Column types for `mysql` / `mariadb`](#column-types-for-mysql--mariadb)
|
||||
- [Column types for `postgres`](#column-types-for-postgres)
|
||||
- [Column types for `cockroachdb`](#column-types-for-cockroachdb)
|
||||
- [Column types for `sqlite` / `cordova` / `react-native` / `expo`](#column-types-for-sqlite--cordova--react-native--expo)
|
||||
- [Column types for `mssql`](#column-types-for-mssql)
|
||||
- [Column types for `oracle`](#column-types-for-oracle)
|
||||
- [Column types for `sap`](#column-types-for-sap)
|
||||
- [Column types for `spanner`](#column-types-for-spanner)
|
||||
- [`enum` column type](#enum-column-type)
|
||||
- [`set` column type](#set-column-type)
|
||||
- [`simple-array` column type](#simple-array-column-type)
|
||||
- [`simple-json` column type](#simple-json-column-type)
|
||||
- [Columns with generated values](#columns-with-generated-values)
|
||||
- [Column options](#column-options)
|
||||
- [Entity inheritance](#entity-inheritance)
|
||||
- [Tree entities](#tree-entities)
|
||||
- [Adjacency list](#adjacency-list)
|
||||
- [Closure table](#closure-table)
|
||||
|
||||
## What is Entity?
|
||||
## What is an Entity?
|
||||
|
||||
Entity is a class that maps to a database table (or collection when using MongoDB).
|
||||
You can create an entity by defining a new class and mark it with `@Entity()`:
|
||||
@ -104,7 +78,7 @@ If you want to set a base prefix for all database tables in your application you
|
||||
|
||||
When using an entity constructor its arguments **must be optional**. Since ORM creates instances of entity classes when loading from the database, therefore it is not aware of your constructor arguments.
|
||||
|
||||
Learn more about parameters `@Entity` in [Decorators reference](decorator-reference.md).
|
||||
Learn more about parameters `@Entity` in [Decorators reference](../help/3-decorator-reference.md).
|
||||
|
||||
## Entity columns
|
||||
|
||||
@ -242,7 +216,7 @@ thing.linestring = "LINESTRING(0 0,1 1,2 2)"
|
||||
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 TypeORM built in [GeoJSON types](../src/driver/types/GeoJsonTypes.ts).
|
||||
types](https://www.npmjs.com/package/@types/geojson) or using TypeORM built in [GeoJSON types](../../../src/driver/types/GeoJsonTypes.ts).
|
||||
|
||||
```typescript
|
||||
import {
|
||||
@ -1,9 +1,5 @@
|
||||
# Entity Inheritance
|
||||
|
||||
- [Concrete Table Inheritance](#concrete-table-inheritance)
|
||||
- [Single Table Inheritance](#single-table-inheritance)
|
||||
- [Using embeddeds](#using-embeddeds)
|
||||
|
||||
## Concrete Table Inheritance
|
||||
|
||||
You can reduce duplication in your code by using entity inheritance patterns.
|
||||
@ -158,4 +154,4 @@ will be saved into this table.
|
||||
## Using embeddeds
|
||||
|
||||
There is an amazing way to reduce duplication in your app (using composition over inheritance) by using `embedded columns`.
|
||||
Read more about embedded entities [here](./embedded-entities.md).
|
||||
Read more about embedded entities [here](./2-embedded-entities.md).
|
||||
@ -3,12 +3,6 @@
|
||||
TypeORM supports the Adjacency list and Closure table patterns for storing tree structures.
|
||||
To learn more about the hierarchy table take a look at [this awesome presentation by Bill Karwin](https://www.slideshare.net/billkarwin/models-for-hierarchical-data).
|
||||
|
||||
- [Adjacency list](#adjacency-list)
|
||||
- [Nested set](#nested-set)
|
||||
- [Materialized Path (aka Path Enumeration)](#materialized-path-aka-path-enumeration)
|
||||
- [Closure table](#closure-table)
|
||||
- [Working with tree entities](#working-with-tree-entities)
|
||||
|
||||
## Adjacency list
|
||||
|
||||
Adjacency list is a simple model with self-referencing.
|
||||
@ -232,10 +226,14 @@ There are other special methods to work with tree entities through `TreeReposito
|
||||
- `findTrees` - Returns all trees in the database with all their children, children of children, etc.
|
||||
|
||||
```typescript
|
||||
const treeCategories = await dataSource.manager.getTreeRepository(Category).findTrees()
|
||||
const treeCategories = await dataSource.manager
|
||||
.getTreeRepository(Category)
|
||||
.findTrees()
|
||||
// returns root categories with sub categories inside
|
||||
|
||||
const treeCategoriesWithLimitedDepth = await dataSource.manager.getTreeRepository(Category).findTrees({ depth: 2 })
|
||||
const treeCategoriesWithLimitedDepth = await dataSource.manager
|
||||
.getTreeRepository(Category)
|
||||
.findTrees({ depth: 2 })
|
||||
// returns root categories with sub categories inside, up to depth 2
|
||||
```
|
||||
|
||||
@ -243,14 +241,18 @@ const treeCategoriesWithLimitedDepth = await dataSource.manager.getTreeRepositor
|
||||
Does not load children's leaves.
|
||||
|
||||
```typescript
|
||||
const rootCategories = await dataSource.manager.getTreeRepository(Category).findRoots()
|
||||
const rootCategories = await dataSource.manager
|
||||
.getTreeRepository(Category)
|
||||
.findRoots()
|
||||
// returns root categories without sub categories inside
|
||||
```
|
||||
|
||||
- `findDescendants` - Gets all children (descendants) of the given entity. Returns them all in a flat array.
|
||||
|
||||
```typescript
|
||||
const children = await dataSource.manager.getTreeRepository(Category).findDescendants(parentCategory)
|
||||
const children = await dataSource.manager
|
||||
.getTreeRepository(Category)
|
||||
.findDescendants(parentCategory)
|
||||
// returns all direct subcategories (without its nested categories) of a parentCategory
|
||||
```
|
||||
|
||||
@ -282,7 +284,9 @@ const children = await repository
|
||||
- `countDescendants` - Gets the number of descendants of the entity.
|
||||
|
||||
```typescript
|
||||
const childrenCount = await dataSource.manager.getTreeRepository(Category).countDescendants(parentCategory)
|
||||
const childrenCount = await dataSource.manager
|
||||
.getTreeRepository(Category)
|
||||
.countDescendants(parentCategory)
|
||||
```
|
||||
|
||||
- `findAncestors` - Gets all parents (ancestors) of the given entity. Returns them all in a flat array.
|
||||
@ -295,7 +299,9 @@ const parents = await repository.findAncestors(childCategory)
|
||||
- `findAncestorsTree` - Gets all parents (ancestors) of the given entity. Returns them in a tree - nested into each other.
|
||||
|
||||
```typescript
|
||||
const parentsTree = await dataSource.manager.getTreeRepository(Category).findAncestorsTree(childCategory)
|
||||
const parentsTree = await dataSource.manager
|
||||
.getTreeRepository(Category)
|
||||
.findAncestorsTree(childCategory)
|
||||
// returns all direct childCategory's parent categories (with "parent of parents")
|
||||
```
|
||||
|
||||
@ -311,7 +317,9 @@ const parents = await repository
|
||||
- `countAncestors` - Gets the number of ancestors of the entity.
|
||||
|
||||
```typescript
|
||||
const parentsCount = await dataSource.manager.getTreeRepository(Category).countAncestors(childCategory)
|
||||
const parentsCount = await dataSource.manager
|
||||
.getTreeRepository(Category)
|
||||
.countAncestors(childCategory)
|
||||
```
|
||||
|
||||
For the following methods, options can be passed:
|
||||
@ -330,13 +338,17 @@ The following options are available:
|
||||
Examples:
|
||||
|
||||
```typescript
|
||||
const treeCategoriesWithRelations = await dataSource.manager.getTreeRepository(Category).findTrees({
|
||||
relations: ["sites"],
|
||||
})
|
||||
const treeCategoriesWithRelations = await dataSource.manager
|
||||
.getTreeRepository(Category)
|
||||
.findTrees({
|
||||
relations: ["sites"],
|
||||
})
|
||||
// automatically joins the sites relation
|
||||
|
||||
const parentsWithRelations = await dataSource.manager.getTreeRepository(Category).findAncestors(childCategory, {
|
||||
relations: ["members"],
|
||||
})
|
||||
const parentsWithRelations = await dataSource.manager
|
||||
.getTreeRepository(Category)
|
||||
.findAncestors(childCategory, {
|
||||
relations: ["members"],
|
||||
})
|
||||
// returns all direct childCategory's parent categories (without "parent of parents") and joins the 'members' relation
|
||||
```
|
||||
@ -1,11 +1,6 @@
|
||||
# View Entities
|
||||
|
||||
- [What is View Entity?](#what-is-view-entity)
|
||||
- [View Entity columns](#view-entity-columns)
|
||||
- [View Column options](#view-column-options)
|
||||
- [Complete example](#complete-example)
|
||||
|
||||
## What is View Entity?
|
||||
## What is a ViewEntity?
|
||||
|
||||
View entity is a class that maps to a database view.
|
||||
You can create a view entity by defining a new class and mark it with `@ViewEntity()`:
|
||||
@ -135,7 +130,7 @@ export class PostCategory {
|
||||
|
||||
## View Column options
|
||||
|
||||
View Column options define additional options for your view entity columns, similar to [column options](entities.md#column-options) for regular entities.
|
||||
View Column options define additional options for your view entity columns, similar to [column options](./1-entities.md#column-options) for regular entities.
|
||||
|
||||
You can specify view column options in `@ViewColumn`:
|
||||
|
||||
@ -181,13 +176,14 @@ export class PostCategory {
|
||||
categoryName: string
|
||||
}
|
||||
```
|
||||
|
||||
However, `unique` is currently the only supported option for indices in materialized views. The rest of the indices options will be ignored.
|
||||
|
||||
````typescript
|
||||
```typescript
|
||||
@Index("name-idx", { unique: true })
|
||||
@ViewColumn()
|
||||
name: string
|
||||
````
|
||||
```
|
||||
|
||||
## Complete example
|
||||
|
||||
@ -1,9 +1,5 @@
|
||||
# Separating Entity Definition
|
||||
|
||||
- [Defining Schemas](#defining-schemas)
|
||||
- [Extending Schemas](#extending-schemas)
|
||||
- [Using Schemas](#using-schemas-to-query--insert-data)
|
||||
|
||||
## Defining Schemas
|
||||
|
||||
You can define an entity and its columns right in the model, using decorators.
|
||||
@ -156,7 +152,7 @@ export const CategoryEntity = new EntitySchema<Category>({
|
||||
|
||||
When using the `Decorator` approach it is easy to `extend` basic columns to an abstract class and simply extend this.
|
||||
For example, your `id`, `createdAt` and `updatedAt` columns may be defined in such a `BaseEntity`. For more details, see
|
||||
the documentation on [concrete table inheritance](entity-inheritance.md#concrete-table-inheritance).
|
||||
the documentation on [concrete table inheritance](./3-entity-inheritance.md#concrete-table-inheritance).
|
||||
|
||||
When using the `EntitySchema` approach, this is not possible. However, you can use the `Spread Operator` (`...`) to your
|
||||
advantage.
|
||||
@ -253,11 +249,11 @@ Be sure to add the `extended` columns also to the `Category` interface (e.g., vi
|
||||
|
||||
### Single Table Inheritance
|
||||
|
||||
In order to use [Single Table Inheritance](entity-inheritance.md#single-table-inheritance):
|
||||
In order to use [Single Table Inheritance](./3-entity-inheritance.md#single-table-inheritance):
|
||||
|
||||
1. Add the `inheritance` option to the **parent** class schema, specifying the inheritance pattern ("STI") and the
|
||||
**discriminator** column, which will store the name of the *child* class on each row
|
||||
2. Set the `type: "entity-child"` option for all **children** classes' schemas, while extending the *parent* class
|
||||
**discriminator** column, which will store the name of the _child_ class on each row
|
||||
2. Set the `type: "entity-child"` option for all **children** classes' schemas, while extending the _parent_ class
|
||||
columns using the spread operator syntax described above
|
||||
|
||||
```ts
|
||||
@ -2,35 +2,34 @@
|
||||
|
||||
> By [David Hoeck (@dlhck)](https://github.com/dlhck) and [Michael Bromley (@michaelbromley)](https://github.com/michaelbromley)
|
||||
|
||||
TypeORM is one of the most high-performance, feature-rich, and battle-tested ORMs in the Node.js ecosystem, relied upon by hundreds of thousands of projects and companies worldwide. With nearly 2 million downloads each week, it powers countless applications as a critical dependency. However, over the past few years, maintenance has slowed significantly, leading to growing uncertainty about the project's future among its dedicated community.
|
||||
|
||||
TypeORM is one of the most high-performance, feature-rich, and battle-tested ORMs in the Node.js ecosystem, relied upon by hundreds of thousands of projects and companies worldwide. With nearly 2 million downloads each week, it powers countless applications as a critical dependency. However, over the past few years, maintenance has slowed significantly, leading to growing uncertainty about the project’s future among its dedicated community.
|
||||
|
||||
We’re thrilled to announce that Michael Bromley and David Hoeck, under the umbrella of our parent company [Elevantiq](https://elevantiq.com/), are
|
||||
We're thrilled to announce that Michael Bromley and David Hoeck, under the umbrella of our parent company [Elevantiq](https://elevantiq.com/), are
|
||||
stepping up to lead TypeORM into its next chapter. At Elevantiq, where we
|
||||
specialize in enterprise digital commerce solutions, TypeORM is a critical dependency—not
|
||||
only for [Vendure](https://vendure.io/), our flagship open-source project, but also for many of our other solutions.
|
||||
With our reliance on TypeORM and the growing needs of its vibrant community, we saw an
|
||||
opportunity to contribute back and ensure the project remains active, maintained, and secure.
|
||||
|
||||
After discussions with TypeORM’s original maintainers, Umed and Dmitry, we’ve reached an agreement to take on the project’s maintenance, inspired by successful, community-centric open-source projects. One standout model is [the Tauri project](https://github.com/tauri-apps/tauri), a self-governing open-source initiative co-founded by [Daniel](https://github.com/denjell-crabnebula), who we already collaborate with through Michael and Vendure. Our discussions with Tauri have set the foundation for the organizational structure we envision.
|
||||
After discussions with TypeORM's original maintainers, Umed and Dmitry, we've reached an agreement to take on the project's maintenance, inspired by successful, community-centric open-source projects. One standout model is [the Tauri project](https://github.com/tauri-apps/tauri), a self-governing open-source initiative co-founded by [Daniel](https://github.com/denjell-crabnebula), who we already collaborate with through Michael and Vendure. Our discussions with Tauri have set the foundation for the organizational structure we envision.
|
||||
|
||||
## Our Vision for TypeORM’s Future
|
||||
## Our Vision for TypeORM's Future
|
||||
|
||||
To ensure long-term stability and governance, we plan to establish a non-profit
|
||||
foundation for TypeORM, likely under the [Commons Conservancy](https://commonsconservancy.org/) in the Netherlands.
|
||||
This foundation will be led by a board of seven members: Michael and David,
|
||||
along with five additional board members dedicated to the project’s success.
|
||||
along with five additional board members dedicated to the project's success.
|
||||
The board will work closely with a **Working Group** comprising companies, contributors,
|
||||
and other community members who heavily rely on TypeORM. This collaborative setup will help guide
|
||||
strategic decisions that align with the needs and goals of TypeORM’s ecosystem.
|
||||
strategic decisions that align with the needs and goals of TypeORM's ecosystem.
|
||||
|
||||
## Organizational Structure
|
||||
|
||||
To drive TypeORM forward, we’ll introduce three core domains:
|
||||
To drive TypeORM forward, we'll introduce three core domains:
|
||||
|
||||
- **Development**: Led by core developers with expertise across various database engines and adapters, this team will focus on TypeORM’s architecture and ongoing technical maintenance and advancements.
|
||||
- **Operations**: Handling day-to-day needs, from documentation to sponsorship accounting, this team will keep the project running smoothly.
|
||||
- **Community**: Dedicated to engaging, moderating, and supporting our growing community, this team will foster collaboration through platforms like Discord.
|
||||
- **Development**: Led by core developers with expertise across various database engines and adapters, this team will focus on TypeORM's architecture and ongoing technical maintenance and advancements.
|
||||
- **Operations**: Handling day-to-day needs, from documentation to sponsorship accounting, this team will keep the project running smoothly.
|
||||
- **Community**: Dedicated to engaging, moderating, and supporting our growing community, this team will foster collaboration through platforms like Discord.
|
||||
|
||||
## Scaling Sponsorships and Full-Time Development
|
||||
|
||||
@ -39,12 +38,18 @@ companies and collaborating with organizations like [OSS Pledge](https://opensou
|
||||
employ two full-time developers who will lead the Development team, ensuring ongoing progress
|
||||
and project maintenance.
|
||||
|
||||
We’re confident that, with this structure, we can build a sustainable future for TypeORM. But the
|
||||
We're confident that, with this structure, we can build a sustainable future for TypeORM. But the
|
||||
_success of this vision depends on the support of the community_.
|
||||
We’ll also remain in close contact with [Umed](https://github.com/pleerock) to keep his insights and vision connected to the project’s evolution.
|
||||
We'll also remain in close contact with [Umed](https://github.com/pleerock) to keep his insights and vision connected to the project's evolution.
|
||||
|
||||
## Join Us in Supporting TypeORM
|
||||
|
||||
If your company is interested in starting or expanding its sponsorship with TypeORM, we encourage you to reach out to us directly [via e-mail](mailto:typeorm@elevantiq.com).
|
||||
|
||||
Thank you for your support, and we’re excited to embark on this journey with the TypeORM community!
|
||||
Thank you for your support, and we're excited to embark on this journey with the TypeORM community!
|
||||
|
||||
---
|
||||
|
||||
## Join the Conversation
|
||||
|
||||
Have questions or want to get involved? Join our [Discord community](https://discord.gg/cC9hkmUgNa) or check out our [GitHub repository](https://github.com/typeorm/typeorm).
|
||||
1324
docs/docs/getting-started.md
Normal file
@ -1,9 +1,5 @@
|
||||
# Active Record vs Data Mapper
|
||||
|
||||
- [What is the Active Record pattern?](#what-is-the-active-record-pattern)
|
||||
- [What is the Data Mapper pattern?](#what-is-the-data-mapper-pattern)
|
||||
- [Which one should I choose?](#which-one-should-i-choose)
|
||||
|
||||
## What is the Active Record pattern?
|
||||
|
||||
In TypeORM you can use both the Active Record and the Data Mapper patterns.
|
||||
@ -148,7 +144,7 @@ const timber = await userRepository.findOneBy({
|
||||
})
|
||||
```
|
||||
|
||||
In order to extend standard repository with custom methods, use [custom repository pattern](custom-repository.md).
|
||||
In order to extend standard repository with custom methods, use [custom repository pattern](../working-with-entity-manager/4-custom-repository.md).
|
||||
|
||||
## Which one should I choose?
|
||||
|
||||
@ -1,10 +1,5 @@
|
||||
# MongoDB
|
||||
|
||||
- [MongoDB support](#mongodb-support)
|
||||
- [Defining entities and columns](#defining-entities-and-columns)
|
||||
- [Defining subdocuments (embed documents)](#defining-subdocuments-embed-documents)
|
||||
- [Using `MongoEntityManager` and `MongoRepository`](#using-mongoentitymanager-and-mongorepository)
|
||||
|
||||
## MongoDB support
|
||||
|
||||
TypeORM has basic MongoDB support.
|
||||
@ -1,9 +1,5 @@
|
||||
# Example using TypeORM with Express
|
||||
|
||||
- [Initial setup](#initial-setup)
|
||||
- [Adding Express to the application](#adding-express-to-the-application)
|
||||
- [Adding TypeORM to the application](#adding-typeorm-to-the-application)
|
||||
|
||||
## Initial setup
|
||||
|
||||
Let's create a simple application called "user" which stores users in the database
|
||||
@ -167,7 +163,7 @@ export const myDataSource = new DataSource({
|
||||
```
|
||||
|
||||
Configure each option as you need.
|
||||
Learn more about options [here](./data-source-options.md).
|
||||
Learn more about options [here](../data-source/2-data-source-options.md).
|
||||
|
||||
Let's create a `user.entity.ts` entity inside `src/entity`:
|
||||
|
||||
@ -1,11 +1,5 @@
|
||||
# Migration from Sequelize to TypeORM
|
||||
|
||||
- [Setting up a data source](#setting-up-a-data-source)
|
||||
- [Schema synchronization](#schema-synchronization)
|
||||
- [Creating a models](#creating-a-models)
|
||||
- [Other model settings](#other-model-settings)
|
||||
- [Working with models](#working-with-models)
|
||||
|
||||
## Setting up a data source
|
||||
|
||||
In sequelize you create a data source this way:
|
||||
@ -50,7 +44,7 @@ dataSource
|
||||
|
||||
Then you can use `dataSource` instance from anywhere in your app.
|
||||
|
||||
Learn more about [Data Source](data-source.md)
|
||||
Learn more about [Data Source](../data-source/1-data-source.md)
|
||||
|
||||
## Schema synchronization
|
||||
|
||||
@ -143,7 +137,7 @@ and provides a declarative way to define what part of your model
|
||||
will become part of your database table.
|
||||
The power of TypeScript gives you type hinting and other useful features that you can use in classes.
|
||||
|
||||
Learn more about [Entities and columns](entities.md)
|
||||
Learn more about [Entities and columns](../entity/1-entities.md)
|
||||
|
||||
## Other model settings
|
||||
|
||||
@ -269,7 +263,7 @@ if you want to load an existing entity from the database and replace some of its
|
||||
const employee = await Employee.preload({ id: 1, name: "John Doe" })
|
||||
```
|
||||
|
||||
Learn more about [Active Record vs Data Mapper](active-record-data-mapper.md) and [Repository API](repository-api.md).
|
||||
Learn more about [Active Record vs Data Mapper](./1-active-record-data-mapper.md) and [Repository API](../working-with-entity-manager/6-repository-api.md).
|
||||
|
||||
To access properties in sequelize you do the following:
|
||||
|
||||
@ -308,4 +302,4 @@ In TypeORM you do:
|
||||
export class User {}
|
||||
```
|
||||
|
||||
Learn more about [Indices](indices.md)
|
||||
Learn more about [Indices](../advanced-topics/3-indices.md)
|
||||
@ -1,16 +1,5 @@
|
||||
# FAQ
|
||||
|
||||
- [How do I change a column name in the database?](#how-do-i-change-a-column-name-in-the-database)
|
||||
- [How can I set value of default some function, for example `NOW()`?](#how-can-i-set-the-default-value-to-some-function-for-example-now)
|
||||
- [How to do validation?](#how-to-do-validation)
|
||||
- [What does "owner side" in relations mean or why we need to put `@JoinColumn` and `@JoinTable` decorators?](#what-does-owner-side-in-a-relations-mean-or-why-we-need-to-use-joincolumn-and-jointable)
|
||||
- [How do I add extra columns into many-to-many (junction) table?](#how-do-i-add-extra-columns-into-many-to-many-junction-table)
|
||||
- [How to handle outDir TypeScript compiler option?](#how-to-handle-outdir-typescript-compiler-option)
|
||||
- [How to use TypeORM with ts-node?](#how-to-use-typeorm-with-ts-node)
|
||||
- [How to use Webpack for the backend](#how-to-use-webpack-for-the-backend)
|
||||
- [How to use Vite for the backend](#how-to-use-vite-for-the-backend)
|
||||
- [How to use TypeORM in ESM projects?](#how-to-use-typeorm-in-esm-projects)
|
||||
|
||||
## How do I update a database schema?
|
||||
|
||||
One of the main responsibilities of TypeORM is to keep your database tables in sync with your entities.
|
||||
@ -127,7 +116,7 @@ join column / junction table settings, like join column name or junction table n
|
||||
It's not possible to add extra columns into a table created by a many-to-many relation.
|
||||
You'll need to create a separate entity and bind it using two many-to-one relations with the target entities
|
||||
(the effect will be same as creating a many-to-many table),
|
||||
and add extra columns in there. You can read more about this in [Many-to-Many relations](./many-to-many-relations.md#many-to-many-relations-with-custom-properties).
|
||||
and add extra columns in there. You can read more about this in [Many-to-Many relations](../relations/4-many-to-many-relations.md#many-to-many-relations-with-custom-properties).
|
||||
|
||||
## How to handle outDir TypeScript compiler option?
|
||||
|
||||
@ -276,23 +265,23 @@ On production builds, files are [optimized by default](https://vite.dev/config/b
|
||||
You have 3 options to mitigate this. The 3 options are shown belown as diff to this basic "vite.config.ts"
|
||||
|
||||
```ts
|
||||
import legacy from '@vitejs/plugin-legacy';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import path from 'path';
|
||||
import { defineConfig } from 'vite';
|
||||
import legacy from "@vitejs/plugin-legacy"
|
||||
import vue from "@vitejs/plugin-vue"
|
||||
import path from "path"
|
||||
import { defineConfig } from "vite"
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
build: {
|
||||
sourcemap: true,
|
||||
},
|
||||
plugins: [vue(), legacy()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, './src'),
|
||||
build: {
|
||||
sourcemap: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
plugins: [vue(), legacy()],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
### Option 1: Disable minify
|
||||
@ -1,12 +1,5 @@
|
||||
# Supported platforms
|
||||
|
||||
- [NodeJS](#nodejs)
|
||||
- [Browser](#browser)
|
||||
- [Cordova / PhoneGap / Ionic apps](#cordova--phonegap--ionic-apps)
|
||||
- [React Native](#react-native)
|
||||
- [Expo](#expo)
|
||||
- [NativeScript](#nativescript)
|
||||
|
||||
## NodeJS
|
||||
|
||||
TypeORM was tested on Node.js version 14 and above.
|
||||
@ -1,48 +1,5 @@
|
||||
# Decorator reference
|
||||
|
||||
- [Decorators reference](#decorators-reference)
|
||||
- [Entity decorators](#entity-decorators)
|
||||
- [`@Entity`](#entity)
|
||||
- [`@ViewEntity`](#viewentity)
|
||||
- [Column decorators](#column-decorators)
|
||||
- [`@Column`](#column)
|
||||
- [`@PrimaryColumn`](#primarycolumn)
|
||||
- [`@PrimaryGeneratedColumn`](#primarygeneratedcolumn)
|
||||
- [`@ObjectIdColumn`](#objectidcolumn)
|
||||
- [`@CreateDateColumn`](#createdatecolumn)
|
||||
- [`@UpdateDateColumn`](#updatedatecolumn)
|
||||
- [`@DeleteDateColumn`](#deletedatecolumn)
|
||||
- [`@VersionColumn`](#versioncolumn)
|
||||
- [`@Generated`](#generated)
|
||||
- [`@VirtualColumn`](#virtualcolumn)
|
||||
- [Relation decorators](#relation-decorators)
|
||||
- [`@OneToOne`](#onetoone)
|
||||
- [`@ManyToOne`](#manytoone)
|
||||
- [`@OneToMany`](#onetomany)
|
||||
- [`@ManyToMany`](#manytomany)
|
||||
- [`@JoinColumn`](#joincolumn)
|
||||
- [`@JoinTable`](#jointable)
|
||||
- [`@RelationId`](#relationid)
|
||||
- [Subscriber and listener decorators](#subscriber-and-listener-decorators)
|
||||
- [`@AfterLoad`](#afterload)
|
||||
- [`@BeforeInsert`](#beforeinsert)
|
||||
- [`@AfterInsert`](#afterinsert)
|
||||
- [`@BeforeUpdate`](#beforeupdate)
|
||||
- [`@AfterUpdate`](#afterupdate)
|
||||
- [`@BeforeRemove`](#beforeremove)
|
||||
- [`@AfterRemove`](#afterremove)
|
||||
- [`@BeforeSoftRemove`](#beforesoftremove)
|
||||
- [`@AfterSoftRemove`](#aftersoftremove)
|
||||
- [`@BeforeRecover`](#beforerecover)
|
||||
- [`@AfterRecover`](#afterrecover)
|
||||
- [`@EventSubscriber`](#eventsubscriber)
|
||||
- [Other decorators](#other-decorators)
|
||||
- [`@Index`](#index)
|
||||
- [`@Unique`](#unique)
|
||||
- [`@Check`](#check)
|
||||
- [`@Exclusion`](#exclusion)
|
||||
- [`@ForeignKey`](#foreignkey)
|
||||
|
||||
## Entity decorators
|
||||
|
||||
#### `@Entity`
|
||||
@ -83,7 +40,7 @@ Example:
|
||||
export class User {}
|
||||
```
|
||||
|
||||
Learn more about [Entities](entities.md).
|
||||
Learn more about [Entities](../entity/1-entities.md).
|
||||
|
||||
#### `@ViewEntity`
|
||||
|
||||
@ -143,7 +100,7 @@ export class PostCategory {}
|
||||
export class PostCategory {}
|
||||
```
|
||||
|
||||
Learn more about [View Entities](view-entities.md).
|
||||
Learn more about [View Entities](../entity/5-view-entities.md).
|
||||
|
||||
## Column decorators
|
||||
|
||||
@ -171,7 +128,7 @@ export class User {
|
||||
|
||||
`@Column` accept several options you can use:
|
||||
|
||||
- `type: ColumnType` - Column type. One of the [supported column types](entities.md#column-types).
|
||||
- `type: ColumnType` - Column type. One of the [supported column types](../entity/1-entities.md#column-types).
|
||||
- `name: string` - Column name in the database table.
|
||||
By default, the column name is generated from the name of the property.
|
||||
You can change it by specifying your own name.
|
||||
@ -210,7 +167,7 @@ export class User {
|
||||
- `spatialFeatureType: string` - Optional feature type (`Point`, `Polygon`, `LineString`, `Geometry`) used as a constraint on a spatial column. If not specified, it will behave as though `Geometry` was provided. Used only in PostgreSQL and CockroachDB.
|
||||
- `srid: number` - Optional [Spatial Reference ID](https://postgis.net/docs/using_postgis_dbmanagement.html#spatial_ref_sys) used as a constraint on a spatial column. If not specified, it will default to `0`. Standard geographic coordinates (latitude/longitude in the WGS84 datum) correspond to [EPSG 4326](http://spatialreference.org/ref/epsg/wgs-84/). Used only in PostgreSQL and CockroachDB.
|
||||
|
||||
Learn more about [entity columns](entities.md#entity-columns).
|
||||
Learn more about [entity columns](../entity/1-entities.md#entity-columns).
|
||||
|
||||
#### `@PrimaryColumn`
|
||||
|
||||
@ -239,7 +196,7 @@ export class User {
|
||||
|
||||
> Note: when using `primaryKeyConstraintName` with multiple primary keys, the constraint name must be the same for all primary columns.
|
||||
|
||||
Learn more about [entity columns](entities.md#entity-columns).
|
||||
Learn more about [entity columns](../entity/1-entities.md#entity-columns).
|
||||
|
||||
#### `@PrimaryGeneratedColumn`
|
||||
|
||||
@ -284,7 +241,7 @@ export class User {
|
||||
}
|
||||
```
|
||||
|
||||
Learn more about [entity columns](entities.md#entity-columns).
|
||||
Learn more about [entity columns](../entity/1-entities.md#entity-columns).
|
||||
|
||||
#### `@ObjectIdColumn`
|
||||
|
||||
@ -301,7 +258,7 @@ export class User {
|
||||
}
|
||||
```
|
||||
|
||||
Learn more about [MongoDB](mongodb.md).
|
||||
Learn more about [MongoDB](../guides/2-mongodb.md).
|
||||
|
||||
#### `@CreateDateColumn`
|
||||
|
||||
@ -382,25 +339,28 @@ Special column that is never saved to the database and thus acts as a readonly p
|
||||
Each time you call `find` or `findOne` from the entity manager, the value is recalculated based on the query function that was provided in the VirtualColumn Decorator. The alias argument passed to the query references the exact entity alias of the generated query behind the scenes.
|
||||
|
||||
```typescript
|
||||
@Entity({ name: "companies" })
|
||||
export class Company {
|
||||
@PrimaryColumn("varchar", { length: 50 })
|
||||
name: string;
|
||||
@Entity({ name: "companies", alias: "COMP" })
|
||||
export class Company extends BaseEntity {
|
||||
@PrimaryColumn("varchar", { length: 50 })
|
||||
name: string
|
||||
|
||||
@VirtualColumn({ query: (alias) => `SELECT COUNT("name") FROM "employees" WHERE "companyName" = ${alias}."name"` })
|
||||
totalEmployeesCount: number;
|
||||
@VirtualColumn({
|
||||
query: (alias) =>
|
||||
`SELECT COUNT("name") FROM "employees" WHERE "companyName" = ${alias}.name`,
|
||||
})
|
||||
totalEmployeesCount: number
|
||||
|
||||
@OneToMany((type) => Employee, (employee) => employee.company)
|
||||
employees: Employee[];
|
||||
@OneToMany((type) => Employee, (employee) => employee.company)
|
||||
employees: Employee[]
|
||||
}
|
||||
|
||||
@Entity({ name: "employees" })
|
||||
export class Employee {
|
||||
@PrimaryColumn("varchar", { length: 50 })
|
||||
name: string;
|
||||
export class Employee extends BaseEntity {
|
||||
@PrimaryColumn("varchar", { length: 50 })
|
||||
name: string
|
||||
|
||||
@ManyToOne((type) => Company, (company) => company.employees)
|
||||
company: Company;
|
||||
@ManyToOne((type) => Company, (company) => company.employees)
|
||||
company: Company
|
||||
}
|
||||
```
|
||||
|
||||
@ -425,7 +385,7 @@ export class User {
|
||||
}
|
||||
```
|
||||
|
||||
Learn more about [one-to-one relations](one-to-one-relations.md).
|
||||
Learn more about [one-to-one relations](../relations/2-one-to-one-relations.md).
|
||||
|
||||
#### `@ManyToOne`
|
||||
|
||||
@ -451,7 +411,7 @@ export class Photo {
|
||||
}
|
||||
```
|
||||
|
||||
Learn more about [many-to-one / one-to-many relations](many-to-one-one-to-many-relations.md).
|
||||
Learn more about [many-to-one / one-to-many relations](../relations/3-many-to-one-one-to-many-relations.md).
|
||||
|
||||
#### `@OneToMany`
|
||||
|
||||
@ -477,7 +437,7 @@ export class User {
|
||||
}
|
||||
```
|
||||
|
||||
Learn more about [many-to-one / one-to-many relations](many-to-one-one-to-many-relations.md).
|
||||
Learn more about [many-to-one / one-to-many relations](../relations/3-many-to-one-one-to-many-relations.md).
|
||||
|
||||
#### `@ManyToMany`
|
||||
|
||||
@ -513,7 +473,7 @@ export class Question {
|
||||
}
|
||||
```
|
||||
|
||||
Learn more about [many-to-many relations](many-to-many-relations.md).
|
||||
Learn more about [many-to-many relations](../relations/4-many-to-many-relations.md).
|
||||
|
||||
#### `@JoinColumn`
|
||||
|
||||
@ -528,7 +488,7 @@ export class Post {
|
||||
@JoinColumn({
|
||||
name: "cat_id",
|
||||
referencedColumnName: "name",
|
||||
foreignKeyConstraintName: "fk_cat_id"
|
||||
foreignKeyConstraintName: "fk_cat_id",
|
||||
})
|
||||
category: Category
|
||||
}
|
||||
@ -553,12 +513,12 @@ export class Post {
|
||||
joinColumn: {
|
||||
name: "question",
|
||||
referencedColumnName: "id",
|
||||
foreignKeyConstraintName: "fk_question_categories_questionId"
|
||||
foreignKeyConstraintName: "fk_question_categories_questionId",
|
||||
},
|
||||
inverseJoinColumn: {
|
||||
name: "category",
|
||||
referencedColumnName: "id",
|
||||
foreignKeyConstraintName: "fk_question_categories_categoryId"
|
||||
foreignKeyConstraintName: "fk_question_categories_categoryId",
|
||||
},
|
||||
synchronize: false,
|
||||
})
|
||||
@ -622,7 +582,7 @@ export class Post {
|
||||
}
|
||||
```
|
||||
|
||||
Learn more about [listeners](listeners-and-subscribers.md).
|
||||
Learn more about [listeners](../advanced-topics/4-listeners-and-subscribers.md).
|
||||
|
||||
#### `@BeforeInsert`
|
||||
|
||||
@ -640,7 +600,7 @@ export class Post {
|
||||
}
|
||||
```
|
||||
|
||||
Learn more about [listeners](listeners-and-subscribers.md).
|
||||
Learn more about [listeners](../advanced-topics/4-listeners-and-subscribers.md).
|
||||
|
||||
#### `@AfterInsert`
|
||||
|
||||
@ -658,7 +618,7 @@ export class Post {
|
||||
}
|
||||
```
|
||||
|
||||
Learn more about [listeners](listeners-and-subscribers.md).
|
||||
Learn more about [listeners](../advanced-topics/4-listeners-and-subscribers.md).
|
||||
|
||||
#### `@BeforeUpdate`
|
||||
|
||||
@ -676,7 +636,7 @@ export class Post {
|
||||
}
|
||||
```
|
||||
|
||||
Learn more about [listeners](listeners-and-subscribers.md).
|
||||
Learn more about [listeners](../advanced-topics/4-listeners-and-subscribers.md).
|
||||
|
||||
#### `@AfterUpdate`
|
||||
|
||||
@ -694,7 +654,7 @@ export class Post {
|
||||
}
|
||||
```
|
||||
|
||||
Learn more about [listeners](listeners-and-subscribers.md).
|
||||
Learn more about [listeners](../advanced-topics/4-listeners-and-subscribers.md).
|
||||
|
||||
#### `@BeforeRemove`
|
||||
|
||||
@ -712,7 +672,7 @@ export class Post {
|
||||
}
|
||||
```
|
||||
|
||||
Learn more about [listeners](listeners-and-subscribers.md).
|
||||
Learn more about [listeners](../advanced-topics/4-listeners-and-subscribers.md).
|
||||
|
||||
#### `@AfterRemove`
|
||||
|
||||
@ -730,7 +690,7 @@ export class Post {
|
||||
}
|
||||
```
|
||||
|
||||
Learn more about [listeners](listeners-and-subscribers.md).
|
||||
Learn more about [listeners](../advanced-topics/4-listeners-and-subscribers.md).
|
||||
|
||||
#### `@BeforeSoftRemove`
|
||||
|
||||
@ -748,7 +708,7 @@ export class Post {
|
||||
}
|
||||
```
|
||||
|
||||
Learn more about [listeners](listeners-and-subscribers.md).
|
||||
Learn more about [listeners](../advanced-topics/4-listeners-and-subscribers.md).
|
||||
|
||||
#### `@AfterSoftRemove`
|
||||
|
||||
@ -766,7 +726,7 @@ export class Post {
|
||||
}
|
||||
```
|
||||
|
||||
Learn more about [listeners](listeners-and-subscribers.md).
|
||||
Learn more about [listeners](../advanced-topics/4-listeners-and-subscribers.md).
|
||||
|
||||
#### `@BeforeRecover`
|
||||
|
||||
@ -784,7 +744,7 @@ export class Post {
|
||||
}
|
||||
```
|
||||
|
||||
Learn more about [listeners](listeners-and-subscribers.md).
|
||||
Learn more about [listeners](../advanced-topics/4-listeners-and-subscribers.md).
|
||||
|
||||
#### `@AfterRecover`
|
||||
|
||||
@ -802,7 +762,7 @@ export class Post {
|
||||
}
|
||||
```
|
||||
|
||||
Learn more about [listeners](listeners-and-subscribers.md).
|
||||
Learn more about [listeners](../advanced-topics/4-listeners-and-subscribers.md).
|
||||
|
||||
#### `@EventSubscriber`
|
||||
|
||||
@ -844,7 +804,7 @@ export class PostSubscriber implements EntitySubscriberInterface {
|
||||
}
|
||||
```
|
||||
|
||||
Learn more about [subscribers](listeners-and-subscribers.md).
|
||||
Learn more about [subscribers](../advanced-topics/4-listeners-and-subscribers.md).
|
||||
|
||||
## Other decorators
|
||||
|
||||
@ -887,7 +847,7 @@ export class User {
|
||||
}
|
||||
```
|
||||
|
||||
Learn more about [indices](indices.md).
|
||||
Learn more about [indices](../advanced-topics/3-indices.md).
|
||||
|
||||
#### `@Unique`
|
||||
|
||||
@ -1,39 +1,6 @@
|
||||
# Select using Query Builder
|
||||
|
||||
- [What is `QueryBuilder`](#what-is-querybuilder)
|
||||
- [Important note when using the `QueryBuilder`](#important-note-when-using-the-querybuilder)
|
||||
- [How to create and use a `QueryBuilder`](#how-to-create-and-use-a-querybuilder)
|
||||
- [Getting values using QueryBuilder](#getting-values-using-querybuilder)
|
||||
- [Getting a count](#getting-a-count)
|
||||
- [What are aliases for?](#what-are-aliases-for)
|
||||
- [Using parameters to escape data](#using-parameters-to-escape-data)
|
||||
- [Adding `WHERE` expression](#adding-where-expression)
|
||||
- [Adding `HAVING` expression](#adding-having-expression)
|
||||
- [Adding `ORDER BY` expression](#adding-order-by-expression)
|
||||
- [Adding `GROUP BY` expression](#adding-group-by-expression)
|
||||
- [Adding `LIMIT` expression](#adding-limit-expression)
|
||||
- [Adding `OFFSET` expression](#adding-offset-expression)
|
||||
- [Joining relations](#joining-relations)
|
||||
- [Inner and left joins](#inner-and-left-joins)
|
||||
- [Join without selection](#join-without-selection)
|
||||
- [Joining any entity or table](#joining-any-entity-or-table)
|
||||
- [Joining and mapping functionality](#joining-and-mapping-functionality)
|
||||
- [Getting the generated query](#getting-the-generated-query)
|
||||
- [Getting raw results](#getting-raw-results)
|
||||
- [Streaming result data](#streaming-result-data)
|
||||
- [Using pagination](#using-pagination)
|
||||
- [Set locking](#set-locking)
|
||||
- [Use custom index](#use-custom-index)
|
||||
- [Max execution time](#max-execution-time)
|
||||
- [Partial selection](#partial-selection)
|
||||
- [Using subqueries](#using-subqueries)
|
||||
- [Hidden Columns](#hidden-columns)
|
||||
- [Querying Deleted rows](#querying-deleted-rows)
|
||||
- [Common table expressions](#common-table-expressions)
|
||||
- [Time Travel Queries](#time-travel-queries)
|
||||
- [Debugging](#debugging)
|
||||
|
||||
## What is `QueryBuilder`
|
||||
## What is a QueryBuilder?
|
||||
|
||||
`QueryBuilder` is one of the most powerful features of TypeORM -
|
||||
it allows you to build SQL queries using elegant and convenient syntax,
|
||||
@ -98,7 +65,7 @@ const result = await dataSource
|
||||
|
||||
Note that we uniquely named `:sheepId` and `:cowId` instead of using `:id` twice for different parameters.
|
||||
|
||||
## How to create and use a `QueryBuilder`
|
||||
## How to create and use a QueryBuilder?
|
||||
|
||||
There are several ways how you can create a `Query Builder`:
|
||||
|
||||
@ -187,9 +154,9 @@ There are 5 different `QueryBuilder` types available:
|
||||
```typescript
|
||||
await dataSource
|
||||
.createQueryBuilder()
|
||||
.relation(User,"photos")
|
||||
.relation(User, "photos")
|
||||
.of(id)
|
||||
.loadMany();
|
||||
.loadMany()
|
||||
```
|
||||
|
||||
You can switch between different types of query builder within any of them,
|
||||
@ -927,6 +894,7 @@ Using `take` and `skip` will prevent those issues.
|
||||
QueryBuilder supports both optimistic and pessimistic locking.
|
||||
|
||||
#### Lock modes
|
||||
|
||||
Support of lock modes, and SQL statements they translate to, are listed in the table below (blank cell denotes unsupported). When specified lock mode is not supported, a `LockNotSupportedOnGivenDriverError` error will be thrown.
|
||||
|
||||
```text
|
||||
@ -984,6 +952,7 @@ const users = await dataSource
|
||||
Optimistic locking works in conjunction with both `@Version` and `@UpdatedDate` decorators.
|
||||
|
||||
#### Lock tables
|
||||
|
||||
You can also lock tables using the following method:
|
||||
|
||||
```typescript
|
||||
@ -998,10 +967,10 @@ const users = await dataSource
|
||||
If the Lock Tables argument is provided, only the table that is locked in the FOR UPDATE OF clause is specified.
|
||||
|
||||
### setOnLocked
|
||||
|
||||
Allows you to control what happens when a row is locked. By default, the database will wait for the lock.
|
||||
You can control that behavior by using `setOnLocked`
|
||||
|
||||
|
||||
To not wait:
|
||||
|
||||
```typescript
|
||||
@ -1025,10 +994,11 @@ const users = await dataSource
|
||||
```
|
||||
|
||||
Database support for `setOnLocked` based on [lock mode](#lock-modes):
|
||||
- Postgres: `pessimistic_read`, `pessimistic_write`, `for_no_key_update`, `for_key_share`
|
||||
- MySQL 8+: `pessimistic_read`, `pessimistic_write`
|
||||
- MySQL < 8, Maria DB: `pessimistic_write`
|
||||
- Cockroach: `pessimistic_write` (`nowait` only)
|
||||
|
||||
- Postgres: `pessimistic_read`, `pessimistic_write`, `for_no_key_update`, `for_key_share`
|
||||
- MySQL 8+: `pessimistic_read`, `pessimistic_write`
|
||||
- MySQL < 8, Maria DB: `pessimistic_write`
|
||||
- Cockroach: `pessimistic_write` (`nowait` only)
|
||||
|
||||
## Use custom index
|
||||
|
||||
@ -1215,7 +1185,12 @@ If the model you are querying has a column with the attribute `@DeleteDateColumn
|
||||
Let's say you have the following entity:
|
||||
|
||||
```typescript
|
||||
import { Entity, PrimaryGeneratedColumn, Column, DeleteDateColumn } from "typeorm"
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
DeleteDateColumn,
|
||||
} from "typeorm"
|
||||
|
||||
@Entity()
|
||||
export class User {
|
||||
@ -1250,31 +1225,37 @@ support [common table expressions](https://en.wikipedia.org/wiki/Hierarchical_an
|
||||
, if minimal supported version of your database supports them. Common table expressions aren't supported for Oracle yet.
|
||||
|
||||
```typescript
|
||||
const users = await connection.getRepository(User)
|
||||
.createQueryBuilder('user')
|
||||
.select("user.id", 'id')
|
||||
.addCommonTableExpression(`
|
||||
const users = await connection
|
||||
.getRepository(User)
|
||||
.createQueryBuilder("user")
|
||||
.select("user.id", "id")
|
||||
.addCommonTableExpression(
|
||||
`
|
||||
SELECT "userId" FROM "post"
|
||||
`, 'post_users_ids')
|
||||
`,
|
||||
"post_users_ids",
|
||||
)
|
||||
.where(`user.id IN (SELECT "userId" FROM 'post_users_ids')`)
|
||||
.getMany();
|
||||
.getMany()
|
||||
```
|
||||
|
||||
Result values of `InsertQueryBuilder` or `UpdateQueryBuilder` can be used in Postgres:
|
||||
|
||||
```typescript
|
||||
const insertQueryBuilder = connection.getRepository(User)
|
||||
const insertQueryBuilder = connection
|
||||
.getRepository(User)
|
||||
.createQueryBuilder()
|
||||
.insert({
|
||||
name: 'John Smith'
|
||||
name: "John Smith",
|
||||
})
|
||||
.returning(['id']);
|
||||
.returning(["id"])
|
||||
|
||||
const users = await connection.getRepository(User)
|
||||
.createQueryBuilder('user')
|
||||
.addCommonTableExpression(insertQueryBuilder, 'insert_results')
|
||||
const users = await connection
|
||||
.getRepository(User)
|
||||
.createQueryBuilder("user")
|
||||
.addCommonTableExpression(insertQueryBuilder, "insert_results")
|
||||
.where(`user.id IN (SELECT "id" FROM 'insert_results')`)
|
||||
.getMany();
|
||||
.getMany()
|
||||
```
|
||||
|
||||
## Time Travel Queries
|
||||
@ -1345,9 +1326,8 @@ const queryAndParams = await dataSource
|
||||
Which results in:
|
||||
|
||||
```typescript
|
||||
[
|
||||
"SELECT `user`.`id` as `userId`, `user`.`firstName` as `userFirstName`, `user`.`lastName` as `userLastName` FROM `users` `user` WHERE `user`.`id` = ?",
|
||||
[ 1 ]
|
||||
;[
|
||||
"SELECT `user`.`id` as `userId`, `user`.`firstName` as `userFirstName`, `user`.`lastName` as `userLastName` FROM `users` `user` WHERE `user`.`id` = ?",
|
||||
[1],
|
||||
]
|
||||
```
|
||||
|
||||
@ -1,10 +1,5 @@
|
||||
# Delete using Query Builder
|
||||
|
||||
- [Delete using Query Builder](#delete-using-query-builder)
|
||||
- [`Delete`](#delete)
|
||||
- [`Soft-Delete`](#soft-delete)
|
||||
- [`Restore-Soft-Delete`](#restore-soft-delete)
|
||||
|
||||
### `Delete`
|
||||
|
||||
You can create `DELETE` queries using `QueryBuilder`.
|
||||
@ -33,11 +28,11 @@ Examples:
|
||||
|
||||
```typescript
|
||||
await myDataSource
|
||||
.getRepository(User)
|
||||
.createQueryBuilder()
|
||||
.softDelete()
|
||||
.where("id = :id", { id: 1 })
|
||||
.execute();
|
||||
.getRepository(User)
|
||||
.createQueryBuilder()
|
||||
.softDelete()
|
||||
.where("id = :id", { id: 1 })
|
||||
.execute()
|
||||
```
|
||||
|
||||
### `Restore-Soft-Delete`
|
||||
@ -52,9 +47,9 @@ Examples:
|
||||
|
||||
```typescript
|
||||
await myDataSource
|
||||
.getRepository(User)
|
||||
.createQueryBuilder()
|
||||
.restore()
|
||||
.where("id = :id", { id: 1 })
|
||||
.execute();
|
||||
.getRepository(User)
|
||||
.createQueryBuilder()
|
||||
.restore()
|
||||
.where("id = :id", { id: 1 })
|
||||
.execute()
|
||||
```
|
||||
@ -1,10 +1,6 @@
|
||||
# Working with Query Runner
|
||||
# Query Runner
|
||||
|
||||
- [What is `QueryRunner`](#what-is-queryrunner)
|
||||
- [Creating a new `QueryRunner` instance](#creating-a-new-queryrunner-instance)
|
||||
- [Using `QueryRunner`](#using-queryrunner)
|
||||
|
||||
## What is `QueryRunner`
|
||||
## What is a QueryRunner?
|
||||
|
||||
Each new `QueryRunner` instance takes a single connection from connection pool, if RDBMS supports connection pooling.
|
||||
For databases not supporting connection pools, it uses the same connection across data source.
|
||||
@ -1,21 +1,14 @@
|
||||
# Relations
|
||||
|
||||
* [What are relations](#what-are-relations)
|
||||
* [Relation options](#relation-options)
|
||||
* [Cascades](#cascades)
|
||||
* [Cascade Options](#cascade-options)
|
||||
* [`@JoinColumn` options](#joincolumn-options)
|
||||
* [`@JoinTable` options](#jointable-options)
|
||||
|
||||
## What are relations
|
||||
## What are relations?
|
||||
|
||||
Relations helps you to work with related entities easily.
|
||||
There are several types of relations:
|
||||
|
||||
- [one-to-one](./one-to-one-relations.md) using `@OneToOne`
|
||||
- [many-to-one](./many-to-one-one-to-many-relations.md) using `@ManyToOne`
|
||||
- [one-to-many](./many-to-one-one-to-many-relations.md) using `@OneToMany`
|
||||
- [many-to-many](./many-to-many-relations.md) using `@ManyToMany`
|
||||
- [one-to-one](./2-one-to-one-relations.md) using `@OneToOne`
|
||||
- [many-to-one](./3-many-to-one-one-to-many-relations.md) using `@ManyToOne`
|
||||
- [one-to-many](./3-many-to-one-one-to-many-relations.md) using `@OneToMany`
|
||||
- [many-to-many](./4-many-to-many-relations.md) using `@ManyToMany`
|
||||
|
||||
## Relation options
|
||||
|
||||
@ -26,10 +19,10 @@ There are several options you can specify for relations:
|
||||
- `onDelete: "RESTRICT"|"CASCADE"|"SET NULL"` (default: `RESTRICT`) - specifies how foreign key should behave when referenced object is deleted
|
||||
- `nullable: boolean` (default: `true`) - Indicates whether this relation's column is nullable or not. By default it is nullable.
|
||||
- `orphanedRowAction: "nullify" | "delete" | "soft-delete" | "disable"` (default: `disable`) - When a parent is saved (cascading enabled) without a child/children that still exists in database, this will control what shall happen to them.
|
||||
- _delete_ will remove these children from database.
|
||||
- _soft-delete_ will mark children as soft-deleted.
|
||||
- _nullify_ will remove the relation key.
|
||||
- _disable_ will keep the relation intact. To delete, one has to use their own repository.
|
||||
- _delete_ will remove these children from database.
|
||||
- _soft-delete_ will mark children as soft-deleted.
|
||||
- _nullify_ will remove the relation key.
|
||||
- _disable_ will keep the relation intact. To delete, one has to use their own repository.
|
||||
|
||||
## Cascades
|
||||
|
||||
@ -84,7 +84,7 @@ user.profile = profile
|
||||
await dataSource.manager.save(user)
|
||||
```
|
||||
|
||||
With [cascades](./relations.md#cascades) enabled you can save this relation with only one `save` call.
|
||||
With [cascades](./1-relations.md#cascades) enabled you can save this relation with only one `save` call.
|
||||
|
||||
To load user with profile inside you must specify relation in `FindOptions`:
|
||||
|
||||
@ -98,7 +98,7 @@ photo2.user = user
|
||||
await dataSource.manager.save(photo2)
|
||||
```
|
||||
|
||||
With [cascades](./relations.md#cascades) enabled you can save this relation with only one `save` call.
|
||||
With [cascades](./1-relations.md#cascades) enabled you can save this relation with only one `save` call.
|
||||
|
||||
To load a user with photos inside you must specify the relation in `FindOptions`:
|
||||
|
||||
@ -1,13 +1,6 @@
|
||||
# Many-to-many relations
|
||||
|
||||
- [What are many-to-many relations](#what-are-many-to-many-relations)
|
||||
- [Saving many-to-many relations](#saving-many-to-many-relations)
|
||||
- [Deleting many-to-many relations](#deleting-many-to-many-relations)
|
||||
- [Loading many-to-many relations](#loading-many-to-many-relations)
|
||||
- [Bi-directional relations](#bi-directional-relations)
|
||||
- [Many-to-many relations with custom properties](#many-to-many-relations-with-custom-properties)
|
||||
|
||||
## What are many-to-many relations
|
||||
## What are many-to-many relations?
|
||||
|
||||
Many-to-many is a relation where A contains multiple instances of B, and B contains multiple instances of A.
|
||||
Let's take for example `Question` and `Category` entities.
|
||||
@ -84,7 +77,7 @@ This example will produce following tables:
|
||||
|
||||
## Saving many-to-many relations
|
||||
|
||||
With [cascades](./relations.md#cascades) enabled, you can save this relation with only one `save` call.
|
||||
With [cascades](./1-relations.md#cascades) enabled, you can save this relation with only one `save` call.
|
||||
|
||||
```typescript
|
||||
const category1 = new Category()
|
||||
@ -104,7 +97,7 @@ await dataSource.manager.save(question)
|
||||
|
||||
## Deleting many-to-many relations
|
||||
|
||||
With [cascades](./relations.md#cascades) enabled, you can delete this relation with only one `save` call.
|
||||
With [cascades](./1-relations.md#cascades) enabled, you can delete this relation with only one `save` call.
|
||||
|
||||
To delete a many-to-many relationship between two records, remove it from the corresponding field and save the record.
|
||||
|
||||
@ -113,7 +106,7 @@ const question = await dataSource.getRepository(Question).findOne({
|
||||
relations: {
|
||||
categories: true,
|
||||
},
|
||||
where: { id: 1 }
|
||||
where: { id: 1 },
|
||||
})
|
||||
question.categories = question.categories.filter((category) => {
|
||||
return category.id !== categoryToRemove.id
|
||||
@ -1,13 +1,6 @@
|
||||
# Relations FAQ
|
||||
|
||||
- [How to create self referencing relation](#how-to-create-self-referencing-relation)
|
||||
- [How to use relation id without joining relation](#how-to-use-relation-id-without-joining-relation)
|
||||
- [How to load relations in entities](#how-to-load-relations-in-entities)
|
||||
- [Avoid relation property initializers](#avoid-relation-property-initializers)
|
||||
- [Avoid foreign key constraint creation](#avoid-foreign-key-constraint-creation)
|
||||
- [Avoid circular import errors](#avoid-circular-import-errors)
|
||||
|
||||
## How to create self referencing relation
|
||||
## How to create self referencing relation?
|
||||
|
||||
Self-referencing relations are relations which have a relation to themselves.
|
||||
This is useful when you are storing entities in a tree-like structures.
|
||||
@ -46,7 +39,7 @@ export class Category {
|
||||
}
|
||||
```
|
||||
|
||||
## How to use relation id without joining relation
|
||||
## How to use relation id without joining relation?
|
||||
|
||||
Sometimes you want to have, in your object, the id of the related object without loading it.
|
||||
For example:
|
||||
@ -142,7 +135,7 @@ User {
|
||||
}
|
||||
```
|
||||
|
||||
## How to load relations in entities
|
||||
## How to load relations in entities?
|
||||
|
||||
The easiest way to load your entity relations is to use `relations` option in `FindOptions`:
|
||||
|
||||
@ -172,7 +165,7 @@ Using `QueryBuilder` you can do `innerJoinAndSelect` instead of `leftJoinAndSele
|
||||
(to learn the difference between `LEFT JOIN` and `INNER JOIN` refer to your SQL documentation),
|
||||
you can join relation data by a condition, make ordering, etc.
|
||||
|
||||
Learn more about [`QueryBuilder`](select-query-builder.md).
|
||||
Learn more about [`QueryBuilder`](../query-builder/1-select-query-builder.md).
|
||||
|
||||
## Avoid relation property initializers
|
||||
|
||||
103
docs/docs/sql-tag.md
Normal file
@ -0,0 +1,103 @@
|
||||
# SQL Tag
|
||||
|
||||
TypeORM provides a way to write SQL queries using template literals with automatic parameter handling based on your database type. This feature helps prevent SQL injection while making queries more readable. The SQL tag is implemented as a wrapper around the `.query` method, providing an alternative interface while maintaining the same underlying functionality.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
The `sql` tag is available on DataSource, EntityManager, Repository and QueryRunner instances:
|
||||
|
||||
```typescript
|
||||
const users = await dataSource.sql`SELECT * FROM users WHERE name = ${"John"}`
|
||||
```
|
||||
|
||||
## Parameter Handling
|
||||
|
||||
Parameters are automatically escaped and formatted according to your database type:
|
||||
|
||||
- **PostgreSQL, CockroachDB, Aurora PostgreSQL, MariaDB**: Uses `$1`, `$2`, etc.
|
||||
```typescript
|
||||
// Query becomes: SELECT * FROM users WHERE name = $1
|
||||
const users = await dataSource.sql`SELECT * FROM users WHERE name = ${"John"}`
|
||||
```
|
||||
|
||||
- **MySQL, SQLite, Aurora MySQL**: Uses `?`
|
||||
```typescript
|
||||
// Query becomes: SELECT * FROM users WHERE name = ?
|
||||
const users = await dataSource.sql`SELECT * FROM users WHERE name = ${"John"}`
|
||||
```
|
||||
|
||||
- **Oracle**: Uses `:1`, `:2`, etc.
|
||||
```typescript
|
||||
// Query becomes: SELECT * FROM users WHERE name = :1
|
||||
const users = await dataSource.sql`SELECT * FROM users WHERE name = ${"John"}`
|
||||
```
|
||||
|
||||
- **MSSQL**: Uses `@1`, `@2`, etc.
|
||||
```typescript
|
||||
// Query becomes: SELECT * FROM users WHERE name = @1
|
||||
const users = await dataSource.sql`SELECT * FROM users WHERE name = ${"John"}`
|
||||
```
|
||||
|
||||
### Multiple Parameters
|
||||
|
||||
You can use multiple parameters and complex expressions:
|
||||
|
||||
```typescript
|
||||
const name = "John"
|
||||
const age = 30
|
||||
const active = true
|
||||
const users = await dataSource.sql`
|
||||
SELECT * FROM users
|
||||
WHERE name LIKE ${name + "%"}
|
||||
AND age > ${age}
|
||||
AND is_active = ${active}
|
||||
`
|
||||
```
|
||||
|
||||
### Expanding Parameter Lists
|
||||
|
||||
To transform an array of values into a dynamic list of parameters in a template expression, wrap the array in a function. This is commonly used to write an `IN (...)` expression in SQL, where each value in the list must be supplied as a separate parameter:
|
||||
|
||||
```typescript
|
||||
// Query becomes: SELECT * FROM users WHERE id IN (?, ?, ?)
|
||||
const users = await dataSource.sql`
|
||||
SELECT * FROM users
|
||||
WHERE id IN (${() => [1, 2, 3]})
|
||||
`
|
||||
```
|
||||
|
||||
### Interpolating Unescaped Expressions
|
||||
|
||||
When you want to insert a template expression which should _not_ be transformed into a database parameter, wrap the string in a function. This can be used to dynamically define column, table or schema names which can't be parameterized, or to conditionally set clauses in the SQL.
|
||||
|
||||
**Caution!** No escaping is performed on raw SQL inserted in this way. It is not safe to use this with values sourced from user input.
|
||||
|
||||
```typescript
|
||||
// Query becomes: SELECT * FROM dynamic_table_name
|
||||
const rawData = await dataSource.sql`
|
||||
SELECT * FROM ${() => "dynamic_table_name"}
|
||||
`
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- **SQL Injection Prevention**: Parameters are properly escaped
|
||||
- **Database Agnostic**: Parameter formatting is handled based on your database type
|
||||
- **Readable Queries**: Template literals can make queries more readable than parameter arrays
|
||||
|
||||
## Comparison with Query Method
|
||||
|
||||
The traditional `query` method requires manual parameter placeholder handling:
|
||||
|
||||
```typescript
|
||||
// Traditional query method
|
||||
await dataSource.query(
|
||||
"SELECT * FROM users WHERE name = $1 AND age > $2",
|
||||
["John", 30]
|
||||
)
|
||||
|
||||
// SQL tag alternative
|
||||
await dataSource.sql`SELECT * FROM users WHERE name = ${"John"} AND age > ${30}`
|
||||
```
|
||||
|
||||
The SQL tag handles parameter formatting automatically, which can reduce potential errors.
|
||||
@ -1,4 +1,4 @@
|
||||
# What is EntityManager
|
||||
# EntityManager
|
||||
|
||||
Using `EntityManager` you can manage (insert, update, delete, load, etc.) any entity.
|
||||
EntityManager is just like a collection of all entity repositories in a single place.
|
||||
@ -1,4 +1,4 @@
|
||||
# What is Repository
|
||||
# Repository
|
||||
|
||||
`Repository` is just like `EntityManager` but its operations are limited to a concrete entity.
|
||||
You can access the repository via EntityManager.
|
||||
@ -1,8 +1,5 @@
|
||||
# Find Options
|
||||
|
||||
- [Basic options](#basic-options)
|
||||
- [Advanced options](#advanced-options)
|
||||
|
||||
## Basic options
|
||||
|
||||
All repository and manager ` .find*` methods accept special options you can use to query data you need without using `QueryBuilder`:
|
||||
@ -197,7 +194,7 @@ ORDER BY "columnName" ASC
|
||||
LIMIT 10 OFFSET 0
|
||||
```
|
||||
|
||||
- `cache` - Enables or disables query result caching. See [caching](caching.md) for more information and options.
|
||||
- `cache` - Enables or disables query result caching. See [caching](../query-builder/6-caching.md) for more information and options.
|
||||
|
||||
```typescript
|
||||
userRepository.find({
|
||||
@ -246,7 +243,7 @@ userRepository.findOne({
|
||||
})
|
||||
```
|
||||
|
||||
See [lock modes](./select-query-builder.md#lock-modes) for more information
|
||||
See [lock modes](../query-builder/1-select-query-builder.md#lock-modes) for more information
|
||||
|
||||
Complete example of find options:
|
||||
|
||||
@ -12,7 +12,7 @@ There are several ways how custom repositories can be created.
|
||||
- [How to create custom repository](#how-to-create-custom-repository)
|
||||
- [Using custom repositories in transactions](#using-custom-repositories-in-transactions)
|
||||
|
||||
## How to create custom repository
|
||||
## How to create custom repository?
|
||||
|
||||
It's common practice assigning a repository instance to a globally exported variable,
|
||||
and use this variable across your app, for example:
|
||||
@ -14,7 +14,7 @@ const queryRunner = manager.queryRunner
|
||||
```
|
||||
|
||||
- `transaction` - Provides a transaction where multiple database requests will be executed in a single database transaction.
|
||||
Learn more [Transactions](./transactions.md).
|
||||
Learn more [Transactions](../advanced-topics/2-transactions.md).
|
||||
|
||||
```typescript
|
||||
await manager.transaction(async (manager) => {
|
||||
@ -36,32 +36,32 @@ const rawData = await manager.query(`SELECT * FROM USERS`)
|
||||
// expo, mariadb, mysql, nativescript, react-native,
|
||||
// sap, sqlite, sqljs
|
||||
const rawData = await manager.query(
|
||||
'SELECT * FROM USERS WHERE name = ? and age = ?',
|
||||
[ 'John', 24 ]
|
||||
"SELECT * FROM USERS WHERE name = ? and age = ?",
|
||||
["John", 24],
|
||||
)
|
||||
|
||||
// aurora-postgres, cockroachdb, postgres
|
||||
const rawData = await manager.query(
|
||||
'SELECT * FROM USERS WHERE name = $1 and age = $2',
|
||||
['John', 24]
|
||||
"SELECT * FROM USERS WHERE name = $1 and age = $2",
|
||||
["John", 24],
|
||||
)
|
||||
|
||||
// oracle
|
||||
const rawData = await manager.query(
|
||||
'SELECT * FROM USERS WHERE name = :1 and age = :2',
|
||||
['John', 24]
|
||||
"SELECT * FROM USERS WHERE name = :1 and age = :2",
|
||||
["John", 24],
|
||||
)
|
||||
|
||||
// spanner
|
||||
const rawData = await manager.query(
|
||||
'SELECT * FROM USERS WHERE name = @param0 and age = @param1',
|
||||
[ 'John', 24 ]
|
||||
"SELECT * FROM USERS WHERE name = @param0 and age = @param1",
|
||||
["John", 24],
|
||||
)
|
||||
|
||||
// mssql
|
||||
const rawData = await manager.query(
|
||||
'SELECT * FROM USERS WHERE name = @0 and age = @1',
|
||||
[ 'John', 24 ]
|
||||
"SELECT * FROM USERS WHERE name = @0 and age = @1",
|
||||
["John", 24],
|
||||
)
|
||||
```
|
||||
|
||||
@ -74,7 +74,7 @@ const rawData = await manager.sql`SELECT * FROM USERS WHERE name = ${'John'} and
|
||||
Learn more about using the [SQL Tag syntax](sql-tag.md).
|
||||
|
||||
- `createQueryBuilder` - Creates a query builder use to build SQL queries.
|
||||
Learn more about [QueryBuilder](select-query-builder.md).
|
||||
Learn more about [QueryBuilder](../query-builder/1-select-query-builder.md).
|
||||
|
||||
```typescript
|
||||
const users = await manager
|
||||
@ -355,28 +355,28 @@ await manager.clear(User)
|
||||
```
|
||||
|
||||
- `getRepository` - Gets `Repository` to perform operations on a specific entity.
|
||||
Learn more about [Repositories](working-with-repository.md).
|
||||
Learn more about [Repositories](./2-working-with-repository.md).
|
||||
|
||||
```typescript
|
||||
const userRepository = manager.getRepository(User)
|
||||
```
|
||||
|
||||
- `getTreeRepository` - Gets `TreeRepository` to perform operations on a specific entity.
|
||||
Learn more about [Repositories](working-with-repository.md).
|
||||
Learn more about [Repositories](./2-working-with-repository.md).
|
||||
|
||||
```typescript
|
||||
const categoryRepository = manager.getTreeRepository(Category)
|
||||
```
|
||||
|
||||
- `getMongoRepository` - Gets `MongoRepository` to perform operations on a specific entity.
|
||||
Learn more about [MongoDB](./mongodb.md).
|
||||
Learn more about [MongoDB](../guides/2-mongodb.md).
|
||||
|
||||
```typescript
|
||||
const userRepository = manager.getMongoRepository(User)
|
||||
```
|
||||
|
||||
- `withRepository` - Gets custom repository instance used in a transaction.
|
||||
Learn more about [Custom repositories](custom-repository.md).
|
||||
Learn more about [Custom repositories](./4-custom-repository.md).
|
||||
|
||||
```typescript
|
||||
const myUserRepository = manager.withRepository(UserRepository)
|
||||
@ -1,11 +1,5 @@
|
||||
# Repository APIs
|
||||
|
||||
- [Repository APIs](#repository-apis)
|
||||
- [`Repository` API](#repository-api)
|
||||
- [Additional Options](#additional-options)
|
||||
- [`TreeRepository` API](#treerepository-api)
|
||||
- [`MongoRepository` API](#mongorepository-api)
|
||||
|
||||
## `Repository` API
|
||||
|
||||
- `manager` - The `EntityManager` used by this repository.
|
||||
@ -15,7 +9,6 @@ const manager = repository.manager
|
||||
```
|
||||
|
||||
- `metadata` - The `EntityMetadata` of the entity managed by this repository.
|
||||
Learn more about [transactions in Entity Metadata](./entity-metadata.md).
|
||||
|
||||
```typescript
|
||||
const metadata = repository.metadata
|
||||
@ -36,7 +29,7 @@ const target = repository.target
|
||||
```
|
||||
|
||||
- `createQueryBuilder` - Creates a query builder use to build SQL queries.
|
||||
Learn more about [QueryBuilder](select-query-builder.md).
|
||||
Learn more about [QueryBuilder](../query-builder/1-select-query-builder.md).
|
||||
|
||||
```typescript
|
||||
const users = await repository
|
||||
@ -82,7 +75,7 @@ repository.merge(user, { firstName: "Timber" }, { lastName: "Saw" }) // same as
|
||||
- `preload` - Creates a new entity from the given plain javascript object. If the entity already exists in the database, then
|
||||
it loads it (and everything related to it), replaces all values with the new ones from the given object,
|
||||
and returns the new entity. The new entity is actually an entity loaded from the database with all properties
|
||||
replaced from the new object. <br>
|
||||
replaced from the new object. <br></br>
|
||||
Note that given entity-like object must have an entity id / primary key to find entity by.
|
||||
Returns undefined if entity with given id was not found.
|
||||
|
||||
@ -419,32 +412,32 @@ const rawData = await repository.query(`SELECT * FROM USERS`)
|
||||
// expo, mariadb, mysql, nativescript, react-native,
|
||||
// sap, sqlite, sqljs
|
||||
const rawData = await repository.query(
|
||||
'SELECT * FROM USERS WHERE name = ? and age = ?',
|
||||
[ 'John', 24 ]
|
||||
"SELECT * FROM USERS WHERE name = ? and age = ?",
|
||||
["John", 24],
|
||||
)
|
||||
|
||||
// aurora-postgres, cockroachdb, postgres
|
||||
const rawData = await repository.query(
|
||||
'SELECT * FROM USERS WHERE name = $1 and age = $2',
|
||||
['John', 24]
|
||||
"SELECT * FROM USERS WHERE name = $1 and age = $2",
|
||||
["John", 24],
|
||||
)
|
||||
|
||||
// oracle
|
||||
const rawData = await repository.query(
|
||||
'SELECT * FROM USERS WHERE name = :1 and age = :2',
|
||||
['John', 24]
|
||||
"SELECT * FROM USERS WHERE name = :1 and age = :2",
|
||||
["John", 24],
|
||||
)
|
||||
|
||||
// spanner
|
||||
const rawData = await repository.query(
|
||||
'SELECT * FROM USERS WHERE name = @param0 and age = @param1',
|
||||
[ 'John', 24 ]
|
||||
"SELECT * FROM USERS WHERE name = @param0 and age = @param1",
|
||||
["John", 24],
|
||||
)
|
||||
|
||||
// mssql
|
||||
const rawData = await repository.query(
|
||||
'SELECT * FROM USERS WHERE name = @0 and age = @1',
|
||||
[ 'John', 24 ]
|
||||
"SELECT * FROM USERS WHERE name = @0 and age = @1",
|
||||
["John", 24],
|
||||
)
|
||||
```
|
||||
|
||||
@ -485,8 +478,8 @@ userRepository.remove(users, { chunk: 1000 })
|
||||
|
||||
## `TreeRepository` API
|
||||
|
||||
For `TreeRepository` API refer to [the Tree Entities documentation](./tree-entities.md#working-with-tree-entities).
|
||||
For `TreeRepository` API refer to [the Tree Entities documentation](../entity/4-tree-entities.md#working-with-tree-entities).
|
||||
|
||||
## `MongoRepository` API
|
||||
|
||||
For `MongoRepository` API refer to [the MongoDB documentation](./mongodb.md).
|
||||
For `MongoRepository` API refer to [the MongoDB documentation](../guides/2-mongodb.md).
|
||||
181
docs/docusaurus.config.ts
Normal file
@ -0,0 +1,181 @@
|
||||
import { themes as prismThemes } from "prism-react-renderer"
|
||||
import type { Config } from "@docusaurus/types"
|
||||
import type * as Preset from "@docusaurus/preset-classic"
|
||||
import { redirects } from "./redirects"
|
||||
|
||||
// This runs in Node.js - Don't use client-side code here (browser APIs, JSX...)
|
||||
|
||||
const config: Config = {
|
||||
title: "TypeORM",
|
||||
tagline: "Code with Confidence. Query with Power.",
|
||||
favicon: "img/favicon.ico",
|
||||
|
||||
// Set the production url of your site here
|
||||
url: "https://typeorm.io",
|
||||
// Set the /<baseUrl>/ pathname under which your site is served
|
||||
// For GitHub pages deployment, it is often '/<projectName>/'
|
||||
baseUrl: "/",
|
||||
|
||||
// GitHub pages deployment config.
|
||||
// If you aren't using GitHub pages, you don't need these.
|
||||
organizationName: "typeorm", // Usually your GitHub org/user name.
|
||||
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
|
||||
// may want to replace "en" with "zh-Hans".
|
||||
i18n: {
|
||||
defaultLocale: "en",
|
||||
locales: ["en"],
|
||||
},
|
||||
|
||||
presets: [
|
||||
[
|
||||
"classic",
|
||||
{
|
||||
docs: {
|
||||
sidebarPath: "./sidebars.ts",
|
||||
// Please change this to your repo.
|
||||
// Remove this to remove the "edit this page" links.
|
||||
editUrl:
|
||||
"https://github.com/typeorm/typeorm/tree/master/docs/",
|
||||
},
|
||||
theme: {
|
||||
customCss: "./src/css/custom.css",
|
||||
},
|
||||
} satisfies Preset.Options,
|
||||
],
|
||||
],
|
||||
themes: ["docusaurus-theme-search-typesense"],
|
||||
themeConfig: {
|
||||
// Replace with your project's social card
|
||||
image: "img/typeorm-social-card.jpg",
|
||||
colorMode: {
|
||||
defaultMode: "light",
|
||||
disableSwitch: false,
|
||||
respectPrefersColorScheme: true,
|
||||
},
|
||||
announcementBar: {
|
||||
id: "future_of_typeorm",
|
||||
content:
|
||||
'📣 <b>Announcement: The Future of TypeORM</b> — We\'re excited to share our vision for a revitalized TypeORM! <a rel="noopener noreferrer" href="/docs/future-of-typeorm">Read the full announcement</a>',
|
||||
backgroundColor: "#180028",
|
||||
textColor: "#FFFFFF",
|
||||
isCloseable: true,
|
||||
},
|
||||
navbar: {
|
||||
title: "TypeORM",
|
||||
logo: {
|
||||
alt: "TypeORM Logo",
|
||||
src: "img/typeorm-icon-colored.png",
|
||||
srcDark: "img/typeorm-icon-white.png",
|
||||
width: 46,
|
||||
height: 64,
|
||||
},
|
||||
items: [
|
||||
{
|
||||
type: "docSidebar",
|
||||
sidebarId: "tutorialSidebar",
|
||||
position: "left",
|
||||
label: "Docs",
|
||||
},
|
||||
{
|
||||
href: "https://github.com/typeorm/typeorm",
|
||||
label: "GitHub",
|
||||
position: "right",
|
||||
},
|
||||
],
|
||||
},
|
||||
footer: {
|
||||
style: "dark",
|
||||
links: [
|
||||
{
|
||||
title: "Docs",
|
||||
items: [
|
||||
{
|
||||
label: "Getting started",
|
||||
to: "/docs/getting-started",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Community",
|
||||
items: [
|
||||
{
|
||||
label: "Discord",
|
||||
href: "https://discord.gg/cC9hkmUgNa",
|
||||
},
|
||||
{
|
||||
label: "Stack Overflow",
|
||||
href: "https://stackoverflow.com/questions/tagged/typeorm",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "More",
|
||||
items: [
|
||||
{
|
||||
label: "GitHub",
|
||||
href: "https://github.com/typeorm/typeorm",
|
||||
},
|
||||
{
|
||||
label: "LinkedIn",
|
||||
href: "https://www.linkedin.com/company/typeorm",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
copyright: `Copyright © ${new Date().getFullYear()} TypeORM. Built with Docusaurus.`,
|
||||
},
|
||||
prism: {
|
||||
theme: prismThemes.github,
|
||||
darkTheme: prismThemes.dracula,
|
||||
additionalLanguages: ["typescript", "javascript", "bash", "json"],
|
||||
},
|
||||
typesense: {
|
||||
// Replace this with the name of your index/collection.
|
||||
// It should match the "index_name" entry in the scraper's "config.json" file.
|
||||
typesenseCollectionName: "typeorm-docs",
|
||||
|
||||
typesenseServerConfig: {
|
||||
nodes: [
|
||||
{
|
||||
host: "a46qefxi7yzt3hlbp-1.a1.typesense.net",
|
||||
port: 443,
|
||||
protocol: "https",
|
||||
},
|
||||
{
|
||||
host: "a46qefxi7yzt3hlbp-2.a1.typesense.net",
|
||||
port: 443,
|
||||
protocol: "https",
|
||||
},
|
||||
{
|
||||
host: "a46qefxi7yzt3hlbp-3.a1.typesense.net",
|
||||
port: 443,
|
||||
protocol: "https",
|
||||
},
|
||||
],
|
||||
apiKey: "92eYxk4qbUKgDwS4dHFn1eMWd9qUYfd7", // SEARCH_ONLY_KEY
|
||||
},
|
||||
|
||||
// Optional: Typesense search parameters: https://typesense.org/docs/0.24.0/api/search.html#search-parameters
|
||||
typesenseSearchParameters: {},
|
||||
|
||||
// Optional
|
||||
contextualSearch: true,
|
||||
},
|
||||
} satisfies Preset.ThemeConfig,
|
||||
plugins: [
|
||||
[
|
||||
"@docusaurus/plugin-client-redirects",
|
||||
{
|
||||
redirects,
|
||||
},
|
||||
],
|
||||
],
|
||||
}
|
||||
|
||||
export default config
|
||||
@ -1,5 +0,0 @@
|
||||
# Entity Metadata
|
||||
|
||||
Entity metadata and all related metadata classes contain information about entities,
|
||||
their columns, indices, relations and other entity-related information you can use
|
||||
to create more complex applications or extensions for TypeORM.
|
||||
@ -1,4 +0,0 @@
|
||||
# Documentation
|
||||
|
||||
This directory contains all TypeORM documentation.
|
||||
This documentation is [the TypeORM website](https://typeorm.io/)
|
||||
@ -1,6 +0,0 @@
|
||||
# Internals
|
||||
|
||||
This guide explains how things are working in TypeORM.
|
||||
It will be useful for our contributors.
|
||||
|
||||
TBD.
|
||||
18212
docs/package-lock.json
generated
Normal file
49
docs/package.json
Normal file
@ -0,0 +1,49 @@
|
||||
{
|
||||
"name": "type-orm-docs",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "docusaurus build",
|
||||
"clear": "docusaurus clear",
|
||||
"deploy": "docusaurus deploy",
|
||||
"docusaurus": "docusaurus",
|
||||
"serve": "docusaurus serve",
|
||||
"start": "docusaurus start",
|
||||
"swizzle": "docusaurus swizzle",
|
||||
"typecheck": "tsc",
|
||||
"write-heading-ids": "docusaurus write-heading-ids",
|
||||
"write-translations": "docusaurus write-translations"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.5%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 3 chrome version",
|
||||
"last 3 firefox version",
|
||||
"last 5 safari version"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "3.7.0",
|
||||
"@docusaurus/plugin-client-redirects": "^3.7.0",
|
||||
"@docusaurus/preset-classic": "3.7.0",
|
||||
"@mdx-js/react": "^3.1.0",
|
||||
"clsx": "^2.1.1",
|
||||
"docusaurus-theme-search-typesense": "^0.24.0",
|
||||
"prism-react-renderer": "^2.4.1",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "3.7.0",
|
||||
"@docusaurus/tsconfig": "3.7.0",
|
||||
"@docusaurus/types": "3.7.0",
|
||||
"typescript": "~5.8.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0"
|
||||
}
|
||||
}
|
||||
@ -1,206 +0,0 @@
|
||||
# Performance and optimization in TypeORM
|
||||
|
||||
|
||||
## 1. Introduction to performance optimization
|
||||
|
||||
- In applications using ORM like TypeORM, performance optimization is crucial to ensure the system runs smoothly, minimizes latency, and uses resources efficiently.
|
||||
|
||||
- Common challenges when using ORM include unnecessary data retrieval, N+1 query problems, and not leveraging optimization tools such as indexing or caching.
|
||||
|
||||
- The main goals of optimization include:
|
||||
|
||||
- Reducing the number of SQL queries sent to the database.
|
||||
- Optimizing complex queries to run faster.
|
||||
- Using caching and indexing to speed up data retrieval.
|
||||
- Ensuring efficient data retrieval using appropriate loading methods (Lazy vs. Eager loading).
|
||||
|
||||
## 2. Efficient use of Query Builder
|
||||
|
||||
### 2.1. Avoiding the N+1 Query Problem
|
||||
|
||||
- The N+1 Query Problem occurs when the system executes too many sub-queries for each row of data retrieved.
|
||||
|
||||
- To avoid this, you can use `leftJoinAndSelect` or `innerJoinAndSelect` to combine tables in a single query instead of executing multiple queries.
|
||||
|
||||
```typescript
|
||||
const users = await dataSource.getRepository(User)
|
||||
.createQueryBuilder("user")
|
||||
.leftJoinAndSelect("user.posts", "post")
|
||||
.getMany();
|
||||
```
|
||||
|
||||
- Here, `leftJoinAndSelect` helps retrieve all user posts in a single query rather than many small queries.
|
||||
|
||||
### 2.2. Use `getRawMany()` when only raw data is needed
|
||||
|
||||
- In cases where full objects aren't required, you can use `getRawMany()` to fetch raw data and avoid TypeORM processing too much information.
|
||||
|
||||
```typescript
|
||||
const rawPosts = await dataSource.getRepository(Post)
|
||||
.createQueryBuilder("post")
|
||||
.select("post.title, post.createdAt")
|
||||
.getRawMany();
|
||||
```
|
||||
|
||||
### 2.3. Limit fields using `select`
|
||||
|
||||
- To optimize memory usage and reduce unnecessary data, select only the required fields using `select`.
|
||||
|
||||
```typescript
|
||||
const users = await dataSource.getRepository(User)
|
||||
.createQueryBuilder("user")
|
||||
.select(["user.name", "user.email"])
|
||||
.getMany();
|
||||
```
|
||||
|
||||
## 3. Using indices
|
||||
|
||||
- Indexes speed up query performance in the database by reducing the amount of data scanned. TypeORM supports creating indexes on table columns using the `@Index` decorator.
|
||||
|
||||
### 3.1. Creating an index
|
||||
|
||||
- Indexes can be created directly in entities using the `@Index` decorator.
|
||||
|
||||
```typescript
|
||||
import { Entity, Column, Index } from "typeorm";
|
||||
|
||||
@Entity()
|
||||
@Index(["firstName", "lastName"]) // Composite index
|
||||
export class User {
|
||||
@Column()
|
||||
firstName: string;
|
||||
|
||||
@Column()
|
||||
lastName: string;
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2. Unique index
|
||||
- You can create unique indexes to ensure no duplicate values in a column.
|
||||
|
||||
```typescript
|
||||
@Index(["email"], { unique: true })
|
||||
```
|
||||
|
||||
## 4. Lazy loading and Eager Loading
|
||||
|
||||
TypeORM provides two main methods for loading data relations: Lazy Loading and Eager Loading. Each has a different impact on the performance of your application.
|
||||
|
||||
|
||||
|
||||
|
||||
### 4.1. Lazy loading
|
||||
|
||||
- Lazy loading loads the relation data only when needed, reducing database load when all related data isn't always necessary.
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class User {
|
||||
@OneToMany(() => Post, post => post.user, { lazy: true })
|
||||
posts: Promise<Post[]>;
|
||||
}
|
||||
```
|
||||
|
||||
- When you need to retrieve the data, simply call
|
||||
```typescript
|
||||
const user = await userRepository.findOne(userId);
|
||||
const posts = await user.posts;
|
||||
```
|
||||
|
||||
|
||||
- Advantages:
|
||||
- Resource efficiency: Only loads the necessary data when actually required, reducing query costs and memory usage.
|
||||
- Ideal for selective data usage: Suitable for scenarios where not all related data is needed.
|
||||
- Disadvantages:
|
||||
- Increased query complexity: Each access to related data triggers an additional query to the database, which may increase latency if not managed properly.
|
||||
- Difficult to track: Can lead to the n+1 query problem if used carelessly.
|
||||
|
||||
### 4.2. Eager Loading
|
||||
|
||||
- Eager loading automatically retrieves all related data when the main query is executed. This can be convenient but may cause performance issues if there are too many complex relations.
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class User {
|
||||
@OneToMany(() => Post, post => post.user, { eager: true })
|
||||
posts: Post[];
|
||||
}
|
||||
```
|
||||
|
||||
- In this case, posts will be loaded as soon as user data is retrieved.
|
||||
|
||||
- Advantages:
|
||||
- Automatically loads related data, making it easier to access relationships without additional queries.
|
||||
- Avoids the n+1 query problem: Since all data is fetched in a single query, there's no risk of generating unnecessary multiple queries.
|
||||
- Disadvantages:
|
||||
- Fetching all related data at once may result in large queries, even if not all data is needed.
|
||||
- Not suitable for scenarios where only a subset of related data is required, as it can lead to inefficient data usage.
|
||||
|
||||
- To explore more details and examples of how to configure and use lazy and eager relations, visit the official TypeORM documentation: https://typeorm.io/eager-and-lazy-relations
|
||||
|
||||
## 5. Advanced optimization
|
||||
|
||||
### 5.1. Using Query Hints
|
||||
|
||||
- Query Hints are instructions sent along with SQL queries, helping the database decide on more efficient execution strategies.
|
||||
|
||||
- Different RDBMS systems support different kinds of hints, such as suggesting index usage or choosing the appropriate JOIN type.
|
||||
|
||||
```typescript
|
||||
await dataSource.query(`
|
||||
SELECT /*+ MAX_EXECUTION_TIME(1000) */ *
|
||||
FROM user
|
||||
WHERE email = 'example@example.com'
|
||||
`);
|
||||
```
|
||||
|
||||
- In the example above, `MAX_EXECUTION_TIME(1000)` instructs MySQL to stop the query if it takes more than 1 second.
|
||||
|
||||
### 5.2. Pagination
|
||||
|
||||
- Pagination is a crucial technique for improving performance when retrieving large amounts of data. Instead of fetching all data at once, pagination divides data into smaller pages, reducing database load and optimizing memory usage.
|
||||
|
||||
- In TypeORM, you can use `limit` and `offset` for pagination.
|
||||
|
||||
```typescript
|
||||
const users = await userRepository
|
||||
.createQueryBuilder("user")
|
||||
.limit(10) // Number of records to fetch per page
|
||||
.offset(20) // Skip the first 20 records
|
||||
.getMany();
|
||||
```
|
||||
|
||||
- Pagination helps prevent fetching large amounts of data at once, minimizing latency and optimizing memory usage. When implementing pagination, consider using pagination cursors for more efficient handling of dynamic data.
|
||||
|
||||
### 5.3. Caching
|
||||
|
||||
- Caching is the technique of temporarily storing query results or data for use in future requests without querying the database each time.
|
||||
|
||||
- TypeORM has built-in caching support, and you can customize how caching is used.
|
||||
|
||||
```typescript
|
||||
const users = await userRepository
|
||||
.createQueryBuilder("user")
|
||||
.cache(true) // Enable caching
|
||||
.getMany();
|
||||
```
|
||||
|
||||
- Additionally, you can configure cache duration or use external caching tools like Redis for better efficiency.
|
||||
|
||||
```typescript=
|
||||
const dataSource = new DataSource({
|
||||
type: "mysql",
|
||||
host: "localhost",
|
||||
port: 3306,
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test",
|
||||
cache: {
|
||||
type: "redis",
|
||||
options: {
|
||||
host: "localhost",
|
||||
port: 6379
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
125
docs/redirects.ts
Normal file
@ -0,0 +1,125 @@
|
||||
export const redirects = [
|
||||
{ from: "/docs", to: "/docs/getting-started" },
|
||||
{ from: "/entities", to: "/docs/entity/entities" },
|
||||
{ from: "/embedded-entities", to: "/docs/entity/embedded-entities" },
|
||||
{ from: "/entity-inheritance", to: "/docs/entity/entity-inheritance" },
|
||||
{ from: "/tree-entities", to: "/docs/entity/tree-entities" },
|
||||
{ from: "/view-entities", to: "/docs/entity/view-entities" },
|
||||
{
|
||||
from: "/separating-entity-definition",
|
||||
to: "/docs/entity/separating-entity-definition",
|
||||
},
|
||||
|
||||
{ from: "/relations", to: "/docs/relations/relations" },
|
||||
{
|
||||
from: "/one-to-one-relations",
|
||||
to: "/docs/relations/one-to-one-relations",
|
||||
},
|
||||
{
|
||||
from: "/many-to-one-one-to-many-relations",
|
||||
to: "/docs/relations/many-to-one-one-to-many-relations",
|
||||
},
|
||||
{
|
||||
from: "/many-to-many-relations",
|
||||
to: "/docs/relations/many-to-many-relations",
|
||||
},
|
||||
{
|
||||
from: "/eager-and-lazy-relations",
|
||||
to: "/docs/relations/eager-and-lazy-relations",
|
||||
},
|
||||
{ from: "/relations-faq", to: "/docs/relations/relations-faq" },
|
||||
|
||||
{
|
||||
from: "/working-with-entity-manager",
|
||||
to: "/docs/working-with-entity-manager/working-with-entity-manager",
|
||||
},
|
||||
{
|
||||
from: "/working-with-repository",
|
||||
to: "/docs/working-with-entity-manager/working-with-repository",
|
||||
},
|
||||
{
|
||||
from: "/find-options",
|
||||
to: "/docs/working-with-entity-manager/find-options",
|
||||
},
|
||||
{
|
||||
from: "/custom-repository",
|
||||
to: "/docs/working-with-entity-manager/custom-repository",
|
||||
},
|
||||
{
|
||||
from: "/entity-manager-api",
|
||||
to: "/docs/working-with-entity-manager/entity-manager-api",
|
||||
},
|
||||
{
|
||||
from: "/repository-api",
|
||||
to: "/docs/working-with-entity-manager/repository-api",
|
||||
},
|
||||
|
||||
{
|
||||
from: "/select-query-builder",
|
||||
to: "/docs/query-builder/select-query-builder",
|
||||
},
|
||||
{
|
||||
from: "/insert-query-builder",
|
||||
to: "/docs/query-builder/insert-query-builder",
|
||||
},
|
||||
{
|
||||
from: "/update-query-builder",
|
||||
to: "/docs/query-builder/update-query-builder",
|
||||
},
|
||||
{
|
||||
from: "/delete-query-builder",
|
||||
to: "/docs/query-builder/delete-query-builder",
|
||||
},
|
||||
{
|
||||
from: "/relational-query-builder",
|
||||
to: "/docs/query-builder/relational-query-builder",
|
||||
},
|
||||
{ from: "/caching", to: "/docs/query-builder/caching" },
|
||||
|
||||
{
|
||||
from: "/active-record-data-mapper",
|
||||
to: "/docs/guides/active-record-data-mapper",
|
||||
},
|
||||
{ from: "/mongodb", to: "/docs/guides/mongodb" },
|
||||
{ from: "/validation", to: "/docs/guides/validation" },
|
||||
{ from: "/example-with-express", to: "/docs/guides/example-with-express" },
|
||||
{
|
||||
from: "/usage-with-javascript",
|
||||
to: "/docs/guides/usage-with-javascript",
|
||||
},
|
||||
{ from: "/sequelize-migration", to: "/docs/guides/sequelize-migration" },
|
||||
|
||||
{ from: "/data-source", to: "/docs/data-source/data-source" },
|
||||
{
|
||||
from: "/data-source-options",
|
||||
to: "/docs/data-source/data-source-options",
|
||||
},
|
||||
{
|
||||
from: "/multiple-data-sources",
|
||||
to: "/docs/data-source/multiple-data-sources",
|
||||
},
|
||||
{ from: "/data-source-api", to: "/docs/data-source/data-source-api" },
|
||||
|
||||
{ from: "/migrations", to: "/docs/advanced-topics/migrations" },
|
||||
{ from: "/transactions", to: "/docs/advanced-topics/transactions" },
|
||||
{ from: "/indices", to: "/docs/advanced-topics/indices" },
|
||||
{
|
||||
from: "/listeners-and-subscribers",
|
||||
to: "/docs/advanced-topics/listeners-and-subscribers",
|
||||
},
|
||||
{ from: "/logging", to: "/docs/advanced-topics/logging" },
|
||||
{ from: "/using-cli", to: "/docs/advanced-topics/using-cli" },
|
||||
{
|
||||
from: "/performance-optimizing",
|
||||
to: "/docs/advanced-topics/performance-optimizing",
|
||||
},
|
||||
|
||||
{ from: "/faq", to: "/docs/help/faq" },
|
||||
{ from: "/supported-platforms", to: "/docs/help/supported-platforms" },
|
||||
{ from: "/decorator-reference", to: "/docs/help/decorator-reference" },
|
||||
{ from: "/support", to: "/docs/help/support" },
|
||||
|
||||
{ from: "/getting-started", to: "/docs/getting-started" },
|
||||
{ from: "/future-of-typeorm", to: "/docs/future-of-typeorm" },
|
||||
{ from: "/query-runner", to: "/docs/query-runner" },
|
||||
]
|
||||
73
docs/sidebars.ts
Normal file
@ -0,0 +1,73 @@
|
||||
import type { SidebarsConfig } from "@docusaurus/plugin-content-docs"
|
||||
|
||||
// This runs in Node.js - Don't use client-side code here (browser APIs, JSX...)
|
||||
|
||||
/**
|
||||
* Creating a sidebar enables you to:
|
||||
- create an ordered group of docs
|
||||
- render a sidebar for each doc of that group
|
||||
- provide next/previous navigation
|
||||
|
||||
The sidebars can be generated from the filesystem, or explicitly defined here.
|
||||
|
||||
Create as many sidebars as you want.
|
||||
*/
|
||||
const sidebars: SidebarsConfig = {
|
||||
// Manually defined sidebar with items in a logical order
|
||||
tutorialSidebar: [
|
||||
{
|
||||
type: "doc",
|
||||
id: "getting-started",
|
||||
label: "Getting Started",
|
||||
},
|
||||
{
|
||||
type: "category",
|
||||
label: "Data Source",
|
||||
items: [{ type: "autogenerated", dirName: "data-source" }],
|
||||
},
|
||||
{
|
||||
type: "category",
|
||||
label: "Entity",
|
||||
items: [{ type: "autogenerated", dirName: "entity" }],
|
||||
},
|
||||
{
|
||||
type: "category",
|
||||
label: "Relations",
|
||||
items: [{ type: "autogenerated", dirName: "relations" }],
|
||||
},
|
||||
{
|
||||
type: "category",
|
||||
label: "Working with Entity Manager",
|
||||
items: [
|
||||
{
|
||||
type: "autogenerated",
|
||||
dirName: "working-with-entity-manager",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "category",
|
||||
label: "Query Builder",
|
||||
items: [{ type: "autogenerated", dirName: "query-builder" }],
|
||||
},
|
||||
"query-runner",
|
||||
{
|
||||
type: "category",
|
||||
label: "Guides",
|
||||
items: [{ type: "autogenerated", dirName: "guides" }],
|
||||
},
|
||||
{
|
||||
type: "category",
|
||||
label: "Advanced Topics",
|
||||
items: [{ type: "autogenerated", dirName: "advanced-topics" }],
|
||||
},
|
||||
{
|
||||
type: "category",
|
||||
label: "Help",
|
||||
items: [{ type: "autogenerated", dirName: "help" }],
|
||||
},
|
||||
"future-of-typeorm",
|
||||
],
|
||||
}
|
||||
|
||||
export default sidebars
|
||||
71
docs/src/components/HomepageFeatures/index.tsx
Normal file
@ -0,0 +1,71 @@
|
||||
import type {ReactNode} from 'react';
|
||||
import clsx from 'clsx';
|
||||
import Heading from '@theme/Heading';
|
||||
import styles from './styles.module.css';
|
||||
|
||||
type FeatureItem = {
|
||||
title: string;
|
||||
Svg: React.ComponentType<React.ComponentProps<'svg'>>;
|
||||
description: ReactNode;
|
||||
};
|
||||
|
||||
const FeatureList: FeatureItem[] = [
|
||||
{
|
||||
title: 'Easy to Use',
|
||||
Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default,
|
||||
description: (
|
||||
<>
|
||||
Docusaurus was designed from the ground up to be easily installed and
|
||||
used to get your website up and running quickly.
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Focus on What Matters',
|
||||
Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default,
|
||||
description: (
|
||||
<>
|
||||
Docusaurus lets you focus on your docs, and we'll do the chores. Go
|
||||
ahead and move your docs into the <code>docs</code> directory.
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Powered by React',
|
||||
Svg: require('@site/static/img/undraw_docusaurus_react.svg').default,
|
||||
description: (
|
||||
<>
|
||||
Extend or customize your website layout by reusing React. Docusaurus can
|
||||
be extended while reusing the same header and footer.
|
||||
</>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
function Feature({title, Svg, description}: FeatureItem) {
|
||||
return (
|
||||
<div className={clsx('col col--4')}>
|
||||
<div className="text--center">
|
||||
<Svg className={styles.featureSvg} role="img" />
|
||||
</div>
|
||||
<div className="text--center padding-horiz--md">
|
||||
<Heading as="h3">{title}</Heading>
|
||||
<p>{description}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function HomepageFeatures(): ReactNode {
|
||||
return (
|
||||
<section className={styles.features}>
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
{FeatureList.map((props, idx) => (
|
||||
<Feature key={idx} {...props} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
11
docs/src/components/HomepageFeatures/styles.module.css
Normal file
@ -0,0 +1,11 @@
|
||||
.features {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 2rem 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.featureSvg {
|
||||
height: 200px;
|
||||
width: 200px;
|
||||
}
|
||||
292
docs/src/css/custom.css
Normal file
@ -0,0 +1,292 @@
|
||||
/**
|
||||
* Any CSS included here will be global. The classic template
|
||||
* bundles Infima by default. Infima is a CSS framework designed to
|
||||
* work well for content-centric websites.
|
||||
*/
|
||||
|
||||
/* You can override the default Infima variables here. */
|
||||
:root {
|
||||
--ifm-color-primary: #D94400;
|
||||
--ifm-color-primary-dark: #C33D00;
|
||||
--ifm-color-primary-darker: #B33800;
|
||||
--ifm-color-primary-darkest: #992F00;
|
||||
--ifm-color-primary-light: #E64B00;
|
||||
--ifm-color-primary-lighter: #F25200;
|
||||
--ifm-color-primary-lightest: #FF5E0D;
|
||||
|
||||
/* Secondary color (purple) */
|
||||
--ifm-color-secondary: #2E004B;
|
||||
--ifm-color-secondary-dark: #290043;
|
||||
--ifm-color-secondary-darker: #25003C;
|
||||
--ifm-color-secondary-darkest: #1F0032;
|
||||
--ifm-color-secondary-light: #370059;
|
||||
--ifm-color-secondary-lighter: #410068;
|
||||
--ifm-color-secondary-lightest: #4B0077;
|
||||
|
||||
--ifm-code-font-size: 95%;
|
||||
--docusaurus-highlighted-code-line-bg: rgba(217, 68, 0, 0.1);
|
||||
|
||||
/* Additional UI colors */
|
||||
--ifm-navbar-background-color: rgba(255, 255, 255, 0.8);
|
||||
--ifm-background-color: #FFFFFF;
|
||||
--ifm-footer-background-color: #3D1B54;
|
||||
--ifm-footer-color: #FFFFFF;
|
||||
--ifm-footer-link-color: #FFE6D9; /* Slightly warmer white for better contrast */
|
||||
--ifm-footer-title-color: #FFFFFF;
|
||||
|
||||
/* Enhanced link colors for better contrast */
|
||||
--ifm-link-color: #B33800;
|
||||
--ifm-link-hover-color: #992F00;
|
||||
}
|
||||
|
||||
/* For readability concerns, you should choose a lighter palette in dark mode. */
|
||||
[data-theme='dark'] {
|
||||
--ifm-color-primary: #FF7733;
|
||||
--ifm-color-primary-dark: #FF6619;
|
||||
--ifm-color-primary-darker: #FF5C0D;
|
||||
--ifm-color-primary-darkest: #E64B00;
|
||||
--ifm-color-primary-light: #FF884D;
|
||||
--ifm-color-primary-lighter: #FF9259;
|
||||
--ifm-color-primary-lightest: #FFAD85;
|
||||
|
||||
/* Secondary colors for dark mode */
|
||||
--ifm-color-secondary: #B366CC;
|
||||
--ifm-color-secondary-dark: #A952C4;
|
||||
--ifm-color-secondary-darker: #9F47BA;
|
||||
--ifm-color-secondary-darkest: #8A3AA3;
|
||||
--ifm-color-secondary-light: #BD7AD3;
|
||||
--ifm-color-secondary-lighter: #C78EDA;
|
||||
--ifm-color-secondary-lightest: #DAB3E6;
|
||||
|
||||
--docusaurus-highlighted-code-line-bg: rgba(255, 119, 51, 0.3);
|
||||
|
||||
/* Additional UI colors for dark mode */
|
||||
--ifm-navbar-background-color: rgba(24, 0, 40, 0.8);
|
||||
--ifm-background-color: #180028;
|
||||
--ifm-footer-background-color: #180028;
|
||||
--ifm-footer-color: #FFFFFF;
|
||||
--ifm-footer-link-color: #FFE6D9; /* Warmer white for better contrast */
|
||||
--ifm-footer-title-color: #FFFFFF;
|
||||
--ifm-heading-color: #FFFFFF;
|
||||
|
||||
/* Enhanced link colors for dark mode */
|
||||
--ifm-link-color: #FF884D;
|
||||
--ifm-link-hover-color: #FF9259;
|
||||
}
|
||||
|
||||
|
||||
html .navbar__link:hover {
|
||||
color: var(--ifm-color-primary);
|
||||
}
|
||||
|
||||
/* Logo visibility based on theme */
|
||||
html[data-theme='light'] .dark-mode-only {
|
||||
display: none;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .light-mode-only {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div[role="banner"] {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
div[class*="announcementBarContent_"] b {
|
||||
font-size: 1.05rem;
|
||||
letter-spacing: 0.3px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
div[class*="announcementBarContent_"] a {
|
||||
color: var(--ifm-link-color) !important;
|
||||
}
|
||||
|
||||
div[class*="announcementBarContent_"] a:hover {
|
||||
filter: brightness(110%);
|
||||
text-decoration: none !important;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
/* Close button styling */
|
||||
div[class*="announcementBar"] .close {
|
||||
color: #FFFFFF;
|
||||
opacity: 0.7;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
div[class*="announcementBar"] .close:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 9996 !important;
|
||||
}
|
||||
|
||||
.navbar-sidebar {
|
||||
height: 100vh !important;
|
||||
background: var(--ifm-background-color) !important;
|
||||
z-index: 10000 !important;
|
||||
}
|
||||
|
||||
.navbar-sidebar__backdrop {
|
||||
z-index: 9999 !important;
|
||||
height: 100vh !important;
|
||||
}
|
||||
|
||||
/* TypeSense search positioning */
|
||||
.DocSearch-Container {
|
||||
z-index: 9999 !important;
|
||||
}
|
||||
|
||||
[data-theme='dark'] .navbar {
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* Custom hero section and buttons */
|
||||
.hero--primary {
|
||||
background: linear-gradient(135deg, var(--ifm-color-secondary) 0%, var(--ifm-color-secondary-lightest) 100%);
|
||||
}
|
||||
|
||||
[data-theme='dark'] .hero--primary {
|
||||
background: linear-gradient(135deg, var(--ifm-color-secondary-darkest) 0%, var(--ifm-color-secondary) 100%);
|
||||
}
|
||||
|
||||
.button.button--secondary {
|
||||
background-color: var(--ifm-color-primary);
|
||||
border-color: var(--ifm-color-primary);
|
||||
color: white;
|
||||
font-weight: 600; /* Enhanced weight for better readability */
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.button.button--secondary:hover {
|
||||
background-color: var(--ifm-color-primary-dark);
|
||||
border-color: var(--ifm-color-primary-dark);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(255, 80, 0, 0.3);
|
||||
}
|
||||
|
||||
.button.button--outline {
|
||||
color: var(--ifm-color-primary);
|
||||
border: 1px solid var(--ifm-color-primary);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.hero--primary .button.button--outline {
|
||||
color: white;
|
||||
border: 1px solid white;
|
||||
}
|
||||
|
||||
.button.button--outline:hover {
|
||||
background-color: var(--ifm-color-primary);
|
||||
border-color: var(--ifm-color-primary);
|
||||
color: white;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(255, 80, 0, 0.3);
|
||||
}
|
||||
|
||||
.hero--primary .button.button--outline:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
border-color: white;
|
||||
color: white;
|
||||
box-shadow: 0 5px 15px rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
/* Footer styling */
|
||||
[data-theme='light'] .footer {
|
||||
background: linear-gradient(160deg, #3D1B54 0%, #4E2868 100%) !important;
|
||||
box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
[data-theme='dark'] .footer {
|
||||
background: linear-gradient(160deg, #180028 0%, #2A0045 100%) !important;
|
||||
box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.footer {
|
||||
--ifm-footer-background-color: var(--ifm-footer-background-color);
|
||||
--ifm-footer-color: var(--ifm-footer-color);
|
||||
--ifm-footer-link-color: var(--ifm-footer-link-color);
|
||||
--ifm-footer-title-color: var(--ifm-footer-title-color);
|
||||
position: relative;
|
||||
padding-top: 3rem;
|
||||
padding-bottom: 2rem;
|
||||
}
|
||||
|
||||
/* Direct override for footer link colors with high specificity */
|
||||
.footer .col .footer__title {
|
||||
color: #FFFFFF !important;
|
||||
font-weight: 700 !important;
|
||||
font-size: 1.2rem !important;
|
||||
letter-spacing: 0.5px !important;
|
||||
margin-bottom: 1.2rem !important;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3) !important;
|
||||
}
|
||||
|
||||
.footer .col .footer__item a.footer__link-item,
|
||||
footer a.footer__link-item,
|
||||
.footer__link-item {
|
||||
color: #FFFFFF !important;
|
||||
font-weight: 600 !important;
|
||||
opacity: 0.95 !important;
|
||||
transition: all 0.2s ease !important;
|
||||
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2) !important;
|
||||
position: relative !important;
|
||||
padding: 3px 0 !important;
|
||||
}
|
||||
|
||||
.footer .col .footer__item a.footer__link-item:hover,
|
||||
footer a.footer__link-item:hover,
|
||||
.footer__link-item:hover {
|
||||
color: #FF7733 !important;
|
||||
opacity: 1 !important;
|
||||
text-decoration: none !important;
|
||||
transform: translateX(3px) !important;
|
||||
text-shadow: 0 0 8px rgba(255, 80, 0, 0.4) !important;
|
||||
}
|
||||
|
||||
/* Add more spacing between footer items */
|
||||
.footer .footer__item {
|
||||
margin-top: 0.7rem !important;
|
||||
margin-bottom: 0.7rem !important;
|
||||
}
|
||||
|
||||
/* Make copyright text more visible */
|
||||
.footer .footer__copyright {
|
||||
color: #FFFFFF !important;
|
||||
font-weight: 500 !important;
|
||||
opacity: 0.9 !important;
|
||||
margin-top: 2.5rem !important;
|
||||
padding-top: 1.5rem !important;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.15) !important;
|
||||
}
|
||||
|
||||
/* Add a subtle orange accent line at the top of the footer */
|
||||
.footer:before {
|
||||
content: '';
|
||||
display: block;
|
||||
height: 4px;
|
||||
width: 100%;
|
||||
background: linear-gradient(90deg, #FF5000, #FF7733, #FF5000);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
box-shadow: 0 1px 5px rgba(255, 80, 0, 0.3);
|
||||
}
|
||||
|
||||
/* Ensure announcement bar meets contrast requirements */
|
||||
div[class*="announcementBarContent_"] {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
div[class*="announcementBarContent_"] a {
|
||||
color: #FFE6D9 !important;
|
||||
text-decoration: underline;
|
||||
}
|
||||
393
docs/src/pages/index.module.css
Normal file
@ -0,0 +1,393 @@
|
||||
/**
|
||||
* CSS files with the .module.css suffix will be treated as CSS modules
|
||||
* and scoped locally.
|
||||
*/
|
||||
|
||||
.heroBanner {
|
||||
padding: 4rem 0;
|
||||
text-align: center;
|
||||
color: #FFFFFF;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 996px) {
|
||||
.heroBanner {
|
||||
padding: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.heroContent {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.heroText {
|
||||
flex: 1;
|
||||
padding-right: 2rem;
|
||||
}
|
||||
|
||||
.heroImage {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.heroImage img {
|
||||
width: 80%;
|
||||
max-width: 350px;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 996px) {
|
||||
.buttons {
|
||||
margin: 0 1rem;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.noHorizontalMarginTablet {
|
||||
margin-inline: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.features {
|
||||
padding: 4rem 0;
|
||||
background-color: var(--ifm-color-white);
|
||||
}
|
||||
|
||||
[data-theme='dark'] .features {
|
||||
background-color: var(--ifm-background-color);
|
||||
}
|
||||
|
||||
.featureItem {
|
||||
padding: 1.5rem;
|
||||
margin-bottom: 2rem;
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.featureItem:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
[data-theme='dark'] .featureItem:hover {
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.featureIcon {
|
||||
font-size: 2.5rem;
|
||||
margin-bottom: 1rem;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.featureContent h3 {
|
||||
font-size: 1.3rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.featureContent p {
|
||||
font-size: 0.95rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.codeExampleSection {
|
||||
padding: 5rem 0;
|
||||
background: linear-gradient(165deg, var(--ifm-color-secondary-lightest) 0%, var(--ifm-color-secondary) 100%);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
[data-theme='dark'] .codeExampleSection {
|
||||
background: linear-gradient(165deg, var(--ifm-color-secondary-darkest) 0%, var(--ifm-color-secondary-dark) 100%);
|
||||
}
|
||||
|
||||
.codeExampleContent {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.codeExampleText {
|
||||
max-width: 90%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.codeExampleText h2 {
|
||||
font-size: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.codeExampleText p {
|
||||
font-size: 1.1rem;
|
||||
margin-bottom: 2rem;
|
||||
text-align: center;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.codeTabs {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.codeTabHeader {
|
||||
display: flex;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.codeTabHeader div {
|
||||
padding: 0.75rem 1.25rem;
|
||||
cursor: pointer;
|
||||
font-size: 0.9rem;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.codeTabActive,
|
||||
.codeTabHeader div:hover {
|
||||
background: var(--ifm-color-primary);
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.codeTabContent {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.databasesSection {
|
||||
padding: 5rem 0;
|
||||
background-color: var(--ifm-color-emphasis-0);
|
||||
}
|
||||
|
||||
[data-theme='dark'] .databasesSection {
|
||||
background-color: var(--ifm-background-color);
|
||||
}
|
||||
|
||||
.sectionTitle {
|
||||
text-align: center;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.platformTitle {
|
||||
text-align: center;
|
||||
margin-top: 4rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.platformDescription {
|
||||
text-align: center;
|
||||
max-width: 600px;
|
||||
margin: 0 auto 2rem;
|
||||
color: var(--ifm-color-emphasis-700);
|
||||
}
|
||||
|
||||
.databasesGrid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 160px);
|
||||
gap: 2rem;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto 2rem;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.databaseItem {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 1.5rem;
|
||||
border-radius: 8px;
|
||||
background-color: var(--ifm-color-emphasis-100);
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
|
||||
text-align: center;
|
||||
width: 160px;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.databaseItem:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 5px 0.5px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.databaseLogo {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.databaseLogo img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
object-fit: contain;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.databaseLogo:hover img {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.databaseName {
|
||||
font-weight: 500;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.databaseDescription {
|
||||
font-size: 0.85rem;
|
||||
color: var(--ifm-color-emphasis-600);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (max-width: 996px) {
|
||||
.databasesGrid {
|
||||
grid-template-columns: repeat(4, 140px);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.databasesGrid {
|
||||
gap: 0.5rem;
|
||||
grid-template-columns: repeat(2, 150px);
|
||||
}
|
||||
|
||||
.databaseItem {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.databaseLogo {
|
||||
height: 60px;
|
||||
width: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.databaseItem {
|
||||
min-height: 180px;
|
||||
}
|
||||
}
|
||||
|
||||
.platformsSection {
|
||||
padding: 4rem 0;
|
||||
background: linear-gradient(165deg, var(--ifm-color-primary-lightest) 0%, var(--ifm-color-primary) 100%);
|
||||
color: white;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
[data-theme='dark'] .platformsSection {
|
||||
background: linear-gradient(165deg, var(--ifm-color-primary-darker) 0%, var(--ifm-color-primary) 100%);
|
||||
}
|
||||
|
||||
.platformsDescription {
|
||||
max-width: 800px;
|
||||
margin: 0 auto 2rem;
|
||||
font-size: 1.1rem;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.platformsIcons {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 1.5rem;
|
||||
|
||||
}
|
||||
|
||||
.platformsIcons span {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
padding: 0.75rem 1.25rem;
|
||||
border-radius: 50px;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.platformsIcons span:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.ctaSection {
|
||||
padding: 5rem 0;
|
||||
background-color: var(--ifm-color-white);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
[data-theme='dark'] .ctaSection {
|
||||
background-color: var(--ifm-background-color);
|
||||
}
|
||||
|
||||
.ctaSection h2 {
|
||||
margin-bottom: 1rem;
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.ctaSection p {
|
||||
max-width: 700px;
|
||||
margin: 0 auto 2rem;
|
||||
font-size: 1.1rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.ctaButtons {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 996px) {
|
||||
.heroContent {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.heroText {
|
||||
padding-right: 0;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.heroImage img {
|
||||
max-width: 250px;
|
||||
}
|
||||
|
||||
.codeExampleContent {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.codeExampleText {
|
||||
max-width: 100%;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.platformsIcons {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ctaButtons {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ctaButtons .button {
|
||||
width: 80%;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
}
|
||||
376
docs/src/pages/index.tsx
Normal file
@ -0,0 +1,376 @@
|
||||
import type { ReactNode } from "react"
|
||||
import React from "react"
|
||||
import clsx from "clsx"
|
||||
import Link from "@docusaurus/Link"
|
||||
import useDocusaurusContext from "@docusaurus/useDocusaurusContext"
|
||||
import Layout from "@theme/Layout"
|
||||
import Heading from "@theme/Heading"
|
||||
import CodeBlock from "@theme/CodeBlock"
|
||||
|
||||
import styles from "./index.module.css"
|
||||
|
||||
// Feature section data
|
||||
const features = [
|
||||
{
|
||||
title: "Flexible Patterns",
|
||||
description:
|
||||
"Supports both DataMapper and ActiveRecord patterns, giving you the flexibility to choose what works best for your project.",
|
||||
icon: "⚙️",
|
||||
},
|
||||
{
|
||||
title: "TypeScript First",
|
||||
description:
|
||||
"Built from the ground up with TypeScript support, providing complete type safety for your database models.",
|
||||
icon: "📝",
|
||||
},
|
||||
{
|
||||
title: "Multi-Database Support",
|
||||
description:
|
||||
"Works with MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, MongoDB, and more.",
|
||||
icon: "🗄️",
|
||||
},
|
||||
{
|
||||
title: "Powerful QueryBuilder",
|
||||
description:
|
||||
"Elegant syntax for building complex queries with joins, pagination, and caching.",
|
||||
icon: "🔍",
|
||||
},
|
||||
{
|
||||
title: "Migrations & Schema",
|
||||
description:
|
||||
"First-class support for database migrations with automatic generation.",
|
||||
icon: "🚀",
|
||||
},
|
||||
{
|
||||
title: "Cross-Platform",
|
||||
description:
|
||||
"Works in Node.js, browsers, mobile, and desktop applications.",
|
||||
icon: "🌐",
|
||||
},
|
||||
]
|
||||
|
||||
// Code examples for tabs
|
||||
const codeExamples = {
|
||||
entity: `import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"
|
||||
|
||||
@Entity()
|
||||
export class User {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number
|
||||
|
||||
@Column()
|
||||
firstName: string
|
||||
|
||||
@Column()
|
||||
lastName: string
|
||||
|
||||
@Column()
|
||||
age: number
|
||||
}`,
|
||||
dataMapper: `// Data Mapper approach
|
||||
const userRepository = dataSource.getRepository(User)
|
||||
|
||||
// Create and save a user
|
||||
const user = new User()
|
||||
user.firstName = "Timber"
|
||||
user.lastName = "Saw"
|
||||
user.age = 25
|
||||
await userRepository.save(user)
|
||||
|
||||
// Find all users
|
||||
const allUsers = await userRepository.find()
|
||||
|
||||
// Find user by ID
|
||||
const user = await userRepository.findOneBy({ id: 1 })`,
|
||||
activeRecord: `// Active Record approach
|
||||
import { Entity, BaseEntity, PrimaryGeneratedColumn, Column } from "typeorm"
|
||||
|
||||
@Entity()
|
||||
export class User extends BaseEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number
|
||||
|
||||
@Column()
|
||||
firstName: string
|
||||
|
||||
@Column()
|
||||
lastName: string
|
||||
}
|
||||
|
||||
// Create and save
|
||||
const user = new User()
|
||||
user.firstName = "Timber"
|
||||
user.lastName = "Saw"
|
||||
await user.save()
|
||||
|
||||
// Find all users
|
||||
const users = await User.find()
|
||||
|
||||
// Find specific user
|
||||
const user = await User.findOneBy({ firstName: "Timber" })`,
|
||||
}
|
||||
|
||||
function HomepageHeader() {
|
||||
const { siteConfig } = useDocusaurusContext()
|
||||
return (
|
||||
<header className={clsx("hero hero--primary", styles.heroBanner)}>
|
||||
<div className="container">
|
||||
<div className={styles.heroContent}>
|
||||
<div className={styles.heroText}>
|
||||
<Heading as="h1" className="hero__title">
|
||||
{siteConfig.title}
|
||||
</Heading>
|
||||
<p className="hero__subtitle">{siteConfig.tagline}</p>
|
||||
<div className={styles.buttons}>
|
||||
<Link
|
||||
className="button button--secondary button--lg"
|
||||
to="/docs/getting-started"
|
||||
>
|
||||
Get Started
|
||||
</Link>
|
||||
<Link
|
||||
className="button button--outline button--lg"
|
||||
href="https://github.com/typeorm/typeorm"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
View on GitHub
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.heroImage}>
|
||||
<img
|
||||
src="/img/typeorm-logo-white.svg"
|
||||
alt="TypeORM Logo"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
)
|
||||
}
|
||||
|
||||
function Feature({ title, description, icon }) {
|
||||
return (
|
||||
<div className={clsx("col col--4", styles.featureItem)}>
|
||||
<div className={styles.featureIcon}>{icon}</div>
|
||||
<div className={styles.featureContent}>
|
||||
<Heading as="h3">{title}</Heading>
|
||||
<p>{description}</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function HomepageFeatures() {
|
||||
return (
|
||||
<section className={styles.features}>
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
{features.map((props, idx) => (
|
||||
<Feature key={idx} {...props} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
function CodeExampleSection() {
|
||||
const [activeTab, setActiveTab] = React.useState("entity")
|
||||
|
||||
const handleTabClick = (tab) => {
|
||||
setActiveTab(tab)
|
||||
}
|
||||
|
||||
return (
|
||||
<section className={styles.codeExampleSection}>
|
||||
<div className="container">
|
||||
<div className={styles.codeExampleContent}>
|
||||
<div className={styles.codeExampleText}>
|
||||
<Heading as="h2">Elegant, Type-Safe API</Heading>
|
||||
<p>
|
||||
TypeORM provides a beautiful, simple API for
|
||||
interacting with your database that takes full
|
||||
advantage of TypeScript's type system. Choose
|
||||
between DataMapper and ActiveRecord patterns - both
|
||||
are fully supported.
|
||||
</p>
|
||||
<div className={styles.codeTabs}>
|
||||
<div className={styles.codeTabHeader}>
|
||||
<div
|
||||
className={clsx(
|
||||
activeTab === "entity" &&
|
||||
styles.codeTabActive,
|
||||
)}
|
||||
onClick={() => handleTabClick("entity")}
|
||||
>
|
||||
Entity Definition
|
||||
</div>
|
||||
<div
|
||||
className={clsx(
|
||||
activeTab === "dataMapper" &&
|
||||
styles.codeTabActive,
|
||||
)}
|
||||
onClick={() => handleTabClick("dataMapper")}
|
||||
>
|
||||
Data Mapper
|
||||
</div>
|
||||
<div
|
||||
className={clsx(
|
||||
activeTab === "activeRecord" &&
|
||||
styles.codeTabActive,
|
||||
)}
|
||||
onClick={() =>
|
||||
handleTabClick("activeRecord")
|
||||
}
|
||||
>
|
||||
Active Record
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.codeTabContent}>
|
||||
<CodeBlock language="typescript">
|
||||
{codeExamples[activeTab]}
|
||||
</CodeBlock>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
function SupportedDatabases() {
|
||||
const databases = [
|
||||
{ name: "MySQL", icon: "/img/databases/mysql.png", category: "core" },
|
||||
{
|
||||
name: "PostgreSQL",
|
||||
icon: "/img/databases/postgresql.png",
|
||||
category: "core",
|
||||
},
|
||||
{
|
||||
name: "MariaDB",
|
||||
icon: "/img/databases/mariadb.png",
|
||||
category: "core",
|
||||
},
|
||||
{ name: "SQLite", icon: "/img/databases/sqlite.png", category: "core" },
|
||||
{
|
||||
name: "MS SQL Server",
|
||||
icon: "/img/databases/mssql.png",
|
||||
category: "core",
|
||||
},
|
||||
{ name: "Oracle", icon: "/img/databases/oracle.png", category: "core" },
|
||||
{
|
||||
name: "MongoDB",
|
||||
icon: "/img/databases/mongodb.png",
|
||||
category: "core",
|
||||
},
|
||||
{
|
||||
name: "CockroachDB",
|
||||
icon: "/img/databases/cockroachdb.png",
|
||||
category: "core",
|
||||
},
|
||||
{ name: "SAP HANA", icon: "/img/databases/sap.png", category: "core" },
|
||||
{
|
||||
name: "Google Spanner",
|
||||
icon: "/img/databases/spanner.svg",
|
||||
category: "core",
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<section className={styles.databasesSection}>
|
||||
<div className="container">
|
||||
<Heading as="h2" className={styles.sectionTitle}>
|
||||
Supported Databases
|
||||
</Heading>
|
||||
<div className={styles.databasesGrid}>
|
||||
{databases.map((db, index) => (
|
||||
<div key={index} className={styles.databaseItem}>
|
||||
<div className={styles.databaseLogo}>
|
||||
<img src={db.icon} alt={`${db.name} logo`} />
|
||||
</div>
|
||||
<span className={styles.databaseName}>
|
||||
{db.name}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
function PlatformsSection() {
|
||||
return (
|
||||
<section className={styles.platformsSection}>
|
||||
<div className="container">
|
||||
<Heading as="h2" className={styles.sectionTitle}>
|
||||
Works Everywhere
|
||||
</Heading>
|
||||
<p className={styles.platformsDescription}>
|
||||
TypeORM runs in NodeJS, Browser, Cordova, PhoneGap, Ionic,
|
||||
React Native, NativeScript, Expo, and Electron platforms.
|
||||
</p>
|
||||
<div className={styles.platformsIcons}>
|
||||
<span>🖥️ NodeJS</span>
|
||||
<span>🌐 Browser</span>
|
||||
<span>📱 Mobile</span>
|
||||
<span>⚛️ React Native</span>
|
||||
<span>🖼️ Electron</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
function CallToAction() {
|
||||
return (
|
||||
<section className={styles.ctaSection}>
|
||||
<div className="container">
|
||||
<Heading as="h2">Ready to Get Started?</Heading>
|
||||
<p>
|
||||
TypeORM makes database interaction a breeze. Join thousands
|
||||
of developers who are already building better applications
|
||||
with TypeORM.
|
||||
</p>
|
||||
<div className={styles.ctaButtons}>
|
||||
<Link
|
||||
className={clsx("button button--secondary button--lg margin-right--md", styles.noHorizontalMarginTablet)}
|
||||
to="/docs/getting-started"
|
||||
>
|
||||
Read the Docs
|
||||
</Link>
|
||||
<Link
|
||||
className="button button--outline button--lg"
|
||||
href="https://github.com/typeorm/typeorm"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Star on GitHub
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
export default function Home(): ReactNode {
|
||||
const { siteConfig } = useDocusaurusContext()
|
||||
return (
|
||||
<Layout
|
||||
title={`${siteConfig.title} - ${siteConfig.tagline}`}
|
||||
description="TypeORM is an ORM that can run in NodeJS, Browser, Cordova, PhoneGap, Ionic, React Native, NativeScript, Expo, and Electron platforms and can be used with TypeScript and JavaScript."
|
||||
>
|
||||
<HomepageHeader />
|
||||
<main>
|
||||
<HomepageFeatures />
|
||||
<CodeExampleSection />
|
||||
<SupportedDatabases />
|
||||
<PlatformsSection />
|
||||
<CallToAction />
|
||||
</main>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
7
docs/src/pages/markdown-page.md
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
title: Markdown page example
|
||||
---
|
||||
|
||||
# Markdown page example
|
||||
|
||||
You don't need React to write simple standalone pages.
|
||||
0
docs/static/.nojekyll
vendored
Normal file
BIN
docs/static/img/databases/cockroachdb.png
vendored
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
docs/static/img/databases/mariadb.png
vendored
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
docs/static/img/databases/mongodb.png
vendored
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
BIN
docs/static/img/databases/mssql.png
vendored
Normal file
|
After Width: | Height: | Size: 130 KiB |
BIN
docs/static/img/databases/mysql.png
vendored
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
docs/static/img/databases/oracle.png
vendored
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
docs/static/img/databases/postgresql.png
vendored
Normal file
|
After Width: | Height: | Size: 73 KiB |
BIN
docs/static/img/databases/sap.png
vendored
Normal file
|
After Width: | Height: | Size: 20 KiB |
1
docs/static/img/databases/spanner.svg
vendored
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="64px" height="64px" viewBox="0 0 24 24"><defs><style>.cls-1{fill:#669df6;}.cls-1,.cls-2,.cls-3{fill-rule:evenodd;}.cls-2{fill:#4285f4;}.cls-3{fill:#aecbfa;}</style></defs><title>Icon_24px_CloudSpanner_Color</title><g data-name="Product Icons"><g ><polygon id="Shape-2" data-name="Shape" class="cls-1" points="13.34 12.76 13.34 8.4 10.66 8.4 10.66 12.76 6.89 14.94 8.23 17.26 12 15.08 15.77 17.26 17.11 14.94 13.34 12.76"/><polygon class="cls-2" points="13.34 12.76 13.34 8.4 12 8.4 12 13.52 7.56 16.1 8.23 17.26 12 15.08 15.77 17.26 17.11 14.94 13.34 12.76"/><polygon class="cls-3" points="10.65 2.77 8.62 3.99 8.62 7.72 12 9.55 12 6.44 10.65 5.82 10.65 2.77"/><polygon class="cls-1" points="13.35 5.82 12 6.44 12 9.55 15.38 7.72 15.38 3.99 13.35 2.77 13.35 5.82"/><path class="cls-1" d="M18.14,17.08l-.08,1.39L20.76,20l-2.18,1.2-3.24-1.87.11-3.83,3.27-2L22,15.38,22,17.87l-2.69-1.55Z"/><path class="cls-1" d="M5.86,17.08l-1.17-.76L2,17.87l0-2.49,3.23-1.87,3.27,2,.11,3.83L5.42,21.23,3.24,20l2.7-1.56Z"/><polygon class="cls-3" points="22 17.87 21.95 15.38 18.72 13.52 15.45 15.53 18.14 17.08 19.3 16.32 22 17.87"/><polygon class="cls-3" points="2 17.87 4.7 16.32 5.86 17.08 8.55 15.53 5.28 13.52 2.05 15.38 2 17.87"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
BIN
docs/static/img/databases/sqlite.png
vendored
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
docs/static/img/favicon.ico
vendored
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
docs/static/img/typeorm-icon-colored.png
vendored
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
docs/static/img/typeorm-icon-light.png
vendored
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
docs/static/img/typeorm-icon-white.png
vendored
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
5
docs/static/img/typeorm-logo-colored-dark.svg
vendored
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
5
docs/static/img/typeorm-logo-white.svg
vendored
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
8
docs/tsconfig.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
// This file is not used in compilation. It is here just for a nice editor experience.
|
||||
"extends": "@docusaurus/tsconfig",
|
||||
"compilerOptions": {
|
||||
"baseUrl": "."
|
||||
},
|
||||
"exclude": [".docusaurus", "build"]
|
||||
}
|
||||
1205
docs/zh_CN/README.md
@ -1,183 +0,0 @@
|
||||
# Active Record 与 Data Mapper
|
||||
|
||||
* [什么是Active Record模式?](#什么是Active-Record模式?)
|
||||
* [什么是Data Mapper模式?](#什么是Data-Mapper模式?)
|
||||
* [我应该选择哪一个?](#我应该选择哪一个?)
|
||||
|
||||
## 什么是Active Record模式?
|
||||
|
||||
在 TypeORM 中,你可以使用 Active Record 和 Data Mapper 模式。
|
||||
|
||||
使用 Active Record 方法,你可以在模型本身内定义所有查询方法,并使用模型方法保存、删除和加载对象。
|
||||
|
||||
简单来说,Active Record 模式是一种在模型中访问数据库的方法。
|
||||
你可以在[Wikipedia](https://en.wikipedia.org/wiki/Active_record_pattern)上查看有关 Active Record 模式的更多信息。
|
||||
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from "typeorm";
|
||||
|
||||
@Entity()
|
||||
export class User extends BaseEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
firstName: string;
|
||||
|
||||
@Column()
|
||||
lastName: string;
|
||||
|
||||
@Column()
|
||||
isActive: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
所有 active-record 实体都必须扩展`BaseEntity`类,它提供了与实体一起使用的方法。
|
||||
|
||||
以下示例展示如何使用此类实体:
|
||||
|
||||
```typescript
|
||||
// 示例如何保存AR实体
|
||||
const user = new User();
|
||||
user.firstName = "Timber";
|
||||
user.lastName = "Saw";
|
||||
user.isActive = true;
|
||||
await user.save();
|
||||
|
||||
// 示例如何删除AR实体
|
||||
await user.remove();
|
||||
|
||||
// 示例如何加载AR实体
|
||||
const users = await User.find({ skip: 2, take: 5 });
|
||||
const newUsers = await User.find({ isActive: true });
|
||||
const timber = await User.findOne({ firstName: "Timber", lastName: "Saw" });
|
||||
```
|
||||
|
||||
`BaseEntity`具有标准`Repository`的大部分方法。
|
||||
大多数情况下,你不需要将`Repository`或`EntityManager`与 active record 实体一起使用。
|
||||
|
||||
现在假设我们要创建一个按 first name 和 last name 返回用户的函数。
|
||||
我们可以在`User`类中创建静态方法等函数:
|
||||
|
||||
```typescript
|
||||
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from "typeorm";
|
||||
|
||||
@Entity()
|
||||
export class User extends BaseEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
firstName: string;
|
||||
|
||||
@Column()
|
||||
lastName: string;
|
||||
|
||||
@Column()
|
||||
isActive: boolean;
|
||||
|
||||
static findByName(firstName: string, lastName: string) {
|
||||
return this.createQueryBuilder("user")
|
||||
.where("user.firstName = :firstName", { firstName })
|
||||
.andWhere("user.lastName = :lastName", { lastName })
|
||||
.getMany();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
并像使用其他方法一样使用它:
|
||||
|
||||
```typescript
|
||||
const timber = await User.findByName("Timber", "Saw");
|
||||
```
|
||||
|
||||
## 什么是Data Mapper模式?
|
||||
|
||||
在 TypeORM 中,您可以使用 Active Record 和 Data Mapper 模式。
|
||||
|
||||
使用 Data Mapper 方法,你可以在名为"repositories"的单独类中定义所有查询方法,并使用存储库保存、删除和加载对象。
|
||||
在数据映射器中,你的实体非常笨,它们只是定义了相应的属性,并且可能有一些很笨的方法。
|
||||
|
||||
简单来说,数据映射器是一种在存储库而不是模型中访问数据库的方法。
|
||||
你可以在[Wikipedia](https://en.wikipedia.org/wiki/Data_mapper_pattern)上查看更多关于 data mapper 的信息。
|
||||
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
|
||||
|
||||
@Entity()
|
||||
export class User {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
firstName: string;
|
||||
|
||||
@Column()
|
||||
lastName: string;
|
||||
|
||||
@Column()
|
||||
isActive: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
以下示例展示如何使用此类实体:
|
||||
|
||||
```typescript
|
||||
const userRepository = connection.getRepository(User);
|
||||
|
||||
// 示例如何保存DM实体
|
||||
const user = new User();
|
||||
user.firstName = "Timber";
|
||||
user.lastName = "Saw";
|
||||
user.isActive = true;
|
||||
await userRepository.save(user);
|
||||
|
||||
// 示例如何删除DM实体
|
||||
await userRepository.remove(user);
|
||||
|
||||
// 示例如何加载DM实体
|
||||
const users = await userRepository.find({ skip: 2, take: 5 });
|
||||
const newUsers = await userRepository.find({ isActive: true });
|
||||
const timber = await userRepository.findOne({ firstName: "Timber", lastName: "Saw" });
|
||||
```
|
||||
|
||||
现在假设我们要创建一个按 first name 和 last name 返回用户的函数。
|
||||
我们可以在"custom repository"中创建这样的功能。
|
||||
|
||||
```typescript
|
||||
import { EntityRepository, Repository } from "typeorm";
|
||||
import { User } from "../entity/User";
|
||||
|
||||
@EntityRepository()
|
||||
export class UserRepository extends Repository<User> {
|
||||
findByName(firstName: string, lastName: string) {
|
||||
return this.createQueryBuilder("user")
|
||||
.where("user.firstName = :firstName", { firstName })
|
||||
.andWhere("user.lastName = :lastName", { lastName })
|
||||
.getMany();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
并以这种方式使用它:
|
||||
|
||||
```typescript
|
||||
const userRepository = connection.getCustomRepository(UserRepository);
|
||||
const timber = await userRepository.findByName("Timber", "Saw");
|
||||
```
|
||||
|
||||
了解有关[custom repositories](working-with-entity-manager.md#custom-repositories)的更多信息。
|
||||
|
||||
## 我应该选择哪一个?
|
||||
|
||||
决定取决于你。
|
||||
这两种策略都有自己的缺点和优点。
|
||||
|
||||
在软件开发中我们应该始终牢记的一件事是我们如何维护它。
|
||||
`Data Mapper`方法可以帮助你保持软件的可维护性,这在更大的应用程序中更有效。
|
||||
`Active record`方法可以帮助你保持简单,这在小型应用程序中运行更好。
|
||||
简单性始终是提高可维护性的关键。
|
||||
@ -1,209 +0,0 @@
|
||||
# 缓存查询
|
||||
|
||||
你可以缓存`getMany`,`getOne`,`getRawMany`,`getRawOne`和`getCount`这些`QueryBuilder`方法的查询结果。
|
||||
|
||||
还可以缓存`find`,`findAndCount`,`findByIds`和`count`这些`Repository`方法查询的结果。
|
||||
|
||||
要启用缓存,需要在连接选项中明确启用它:
|
||||
|
||||
```typescript
|
||||
{
|
||||
type: "mysql",
|
||||
host: "localhost",
|
||||
username: "test",
|
||||
...
|
||||
cache: true
|
||||
}
|
||||
```
|
||||
|
||||
首次启用缓存时,你必须同步数据库架构(使用 CLI,migrations 或`synchronize`连接选项)。
|
||||
|
||||
然后在`QueryBuilder`中,你可以为任何查询启用查询缓存:
|
||||
|
||||
```typescript
|
||||
const users = await connection
|
||||
.createQueryBuilder(User, "user")
|
||||
.where("user.isAdmin = :isAdmin", { isAdmin: true })
|
||||
.cache(true)
|
||||
.getMany();
|
||||
```
|
||||
|
||||
等同于`Repository`查询:
|
||||
|
||||
```typescript
|
||||
const users = await connection.getRepository(User).find({
|
||||
where: { isAdmin: true },
|
||||
cache: true
|
||||
});
|
||||
```
|
||||
|
||||
这将执行查询以获取所有 admin users 并缓存结果。
|
||||
下次执行相同的代码时,它将从缓存中获取所有 admin users。
|
||||
默认缓存生存期为`1000 ms`,例如 1 秒。
|
||||
这意味着在调用查询构建器代码后 1 秒内缓存将无效。
|
||||
实际上,这也意味着如果用户在 3 秒内打开用户页面 150 次,则在此期间只会执行三次查询。
|
||||
在 1 秒缓存窗口期间插入的任何 users 都不会返回到 user。
|
||||
|
||||
你可以通过`QueryBuilder`手动更改缓存时间:
|
||||
|
||||
```typescript
|
||||
const users = await connection
|
||||
.createQueryBuilder(User, "user")
|
||||
.where("user.isAdmin = :isAdmin", { isAdmin: true })
|
||||
.cache(60000) // 1 分钟
|
||||
.getMany();
|
||||
```
|
||||
|
||||
或者通过 `Repository`:
|
||||
|
||||
```typescript
|
||||
const users = await connection.getRepository(User).find({
|
||||
where: { isAdmin: true },
|
||||
cache: 60000
|
||||
});
|
||||
```
|
||||
|
||||
或者通过全局连接选项:
|
||||
|
||||
```typescript
|
||||
{
|
||||
type: "mysql",
|
||||
host: "localhost",
|
||||
username: "test",
|
||||
...
|
||||
cache: {
|
||||
duration: 30000 // 30 seconds
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
此外,你可以通过`QueryBuilder`设置"cache id":
|
||||
|
||||
```typescript
|
||||
const users = await connection
|
||||
.createQueryBuilder(User, "user")
|
||||
.where("user.isAdmin = :isAdmin", { isAdmin: true })
|
||||
.cache("users_admins", 25000)
|
||||
.getMany();
|
||||
```
|
||||
|
||||
或者通过 `Repository`:
|
||||
|
||||
```typescript
|
||||
const users = await connection.getRepository(User).find({
|
||||
where: { isAdmin: true },
|
||||
cache: {
|
||||
id: "users_admins",
|
||||
milisseconds: 25000
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
这使你可以精确控制缓存,例如,在插入新用户时清除缓存的结果:
|
||||
|
||||
```typescript
|
||||
await connection.queryResultCache.remove(["users_admins"]);
|
||||
```
|
||||
|
||||
默认情况下,TypeORM 使用一个名为`query-result-cache`的单独表,并在那里存储所有查询和结果。
|
||||
表名是可配置的,因此您可以通过在 tableName 属性中给出值来更改它
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
{
|
||||
type: "mysql",
|
||||
host: "localhost",
|
||||
username: "test",
|
||||
...
|
||||
cache: {
|
||||
type: "database",
|
||||
tableName: "configurable-table-query-result-cache"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
如果在单个数据库表中存储缓存对你无效,则可以将缓存类型更改为"redis"或者"ioredis",而 TypeORM 将以 redis 形式存储所有缓存的记录。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
{
|
||||
type: "mysql",
|
||||
host: "localhost",
|
||||
username: "test",
|
||||
...
|
||||
cache: {
|
||||
type: "redis",
|
||||
options: {
|
||||
host: "localhost",
|
||||
port: 6379
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
"options" 可以是[node_redis specific options](https://github.com/NodeRedis/node_redis#options-object-properties) 或者
|
||||
[ioredis specific options](https://github.com/luin/ioredis/blob/master/API.md#new-redisport-host-options),具体取决于你使用的类型。
|
||||
|
||||
如果你想使用IORedis的集群功能连接到redis-cluster,则可以通过方式下操作来执行此操作:
|
||||
|
||||
```typescript
|
||||
{
|
||||
type: "mysql",
|
||||
host: "localhost",
|
||||
username: "test",
|
||||
cache: {
|
||||
type: "ioredis/cluster",
|
||||
options: {
|
||||
startupNodes: [
|
||||
{
|
||||
host: 'localhost',
|
||||
port: 7000,
|
||||
},
|
||||
{
|
||||
host: 'localhost',
|
||||
port: 7001,
|
||||
},
|
||||
{
|
||||
host: 'localhost',
|
||||
port: 7002,
|
||||
}
|
||||
],
|
||||
options: {
|
||||
scaleReads: 'all',
|
||||
clusterRetryStrategy: function (times) { return null },
|
||||
redisOptions: {
|
||||
maxRetriesPerRequest: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
请注意,你仍然可以使用选项作为IORedis的集群构造函数的第一个参数。
|
||||
|
||||
``` typescript
|
||||
{
|
||||
...
|
||||
cache: {
|
||||
type: "ioredis/cluster",
|
||||
options: [
|
||||
{
|
||||
host: 'localhost',
|
||||
port: 7000,
|
||||
},
|
||||
{
|
||||
host: 'localhost',
|
||||
port: 7001,
|
||||
},
|
||||
{
|
||||
host: 'localhost',
|
||||
port: 7002,
|
||||
}
|
||||
]
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
你可以使用`typeorm cache:clear`来清除存储在缓存中的所有内容。
|
||||
@ -1 +0,0 @@
|
||||
# 更新日志
|
||||
@ -1,427 +0,0 @@
|
||||
# Connection 选项
|
||||
|
||||
- [什么是`ConnectionOptions`](#什么是`ConnectionOptions`)
|
||||
- [常用的连接选项](#常用的连接选项)
|
||||
- [`mysql`/`mariadb`](#mysql/mariadb)
|
||||
- [`postgres`/`cockroachdb`连接选项](#postgres/cockroachdb连接选项)
|
||||
- [`sqlite`](#sqlite)
|
||||
- [`better-sqlite3`](#better-sqlite3)
|
||||
- [`cordova`](#cordova)
|
||||
- [`react-native`](#react-native)
|
||||
- [`nativescript`](#nativescript)
|
||||
- [`mssql`](#mssql)
|
||||
- [`mongodb`](#mongodb)
|
||||
- [`sql.js`](#sqljs)
|
||||
- [`expo`](#expo)
|
||||
- [连接选项示例](#连接选项示例)
|
||||
|
||||
## 什么是`ConnectionOptions`
|
||||
|
||||
连接选项是你传递给`createConnection`或在`ormconfig`文件中定义的连接配置。不同的数据库有自己的特定连接选项。
|
||||
|
||||
## 常用的连接选项
|
||||
|
||||
- `type` - 数据库类型。你必须指定要使用的数据库引擎。该值可以是"mysql","postgres","mariadb","sqlite", "better-sqlite3","cordova","nativescript","oracle","mssql","mongodb","sqljs","react-native"。此选项是**必需**的。
|
||||
|
||||
- `name` - 连接名。 在使用 `getConnection(name: string)`
|
||||
或 `ConnectionManager.get(name: string)`时候需要用到。不同连接的连接名称不能相同,它们都必须是唯一的。如果没有给出连接名称,那么它将被设置为"default"。
|
||||
|
||||
- `extra` - 要传递给底层驱动程序的额外连接选项。如果要将额外设置传递给基础数据库驱动程序,请使用此配置。
|
||||
|
||||
- `entities` - 要加载并用于此连接的实体。接受要加载的实体类和目录路径。目录支持 glob 模式。示例:`entities: [Post, Category, "entity/*.js", "modules/**/entity/*.js"]`。了解有关[entities](./entities.md)的更多信息。
|
||||
|
||||
- `subscribers` - 要加载并用于此连接的订阅者。接受要加载的实体类和目录。目录支持 glob 模式。示例:`subscribers: [PostSubscriber, AppSubscriber, "subscriber/*.js", "modules/**/subscriber/*.js"]`。了解有关[subscribers](listeners-and-subscribers.md)的更多信息。
|
||||
|
||||
- `entitySchemas` - 要加载并用于此连接的实体架构。接受要加载的实体模式类和目录。目录支持 glob 模式。示例:`entitySchemas: [PostSchema, CategorySchema, "entity-schema/*.json"`。了解有关[Entity Schemas](./schema-entity-definition.md)的更多信息。
|
||||
|
||||
- `migrations` - 要加载和用于此连接的迁移。接受要加载的迁移类和目录。目录支持 glob 模式。
|
||||
示例: `migrations: [FirstMigration, SecondMigration, "migration/*.js", "modules/**/migration/*.js"]`.
|
||||
了解有关 [Migrations](./migrations.md)的更多信息。
|
||||
|
||||
- `logging` - 指示是否启用日志记录。如果设置为`true`,则将启用查询和错误日志记录。你还可以指定要启用的不同类型的日志记录,例如`["query", "error", "schema"]`。详细了解[Logging](./logging.md)。
|
||||
|
||||
- `logger` - 记录器,用于日志的记录方式。可能的值是"advanced-console", "simple-console" 和 "file"。默认为"advanced-console"。你还可以指定实现`Logger`接口的记录器类。详细了解[Logging](./logging.md)。
|
||||
|
||||
- `maxQueryExecutionTime` - 如果查询执行时间超过此给定的最大执行时间(以毫秒为单位),则 logger 将记录此查询。
|
||||
|
||||
- `namingStrategy` - 命名策略,用于命名数据 库中的表和列。了解有关[Naming strategies](./naming-strategy.md)的更多信息。
|
||||
|
||||
- `entityPrefix` - 给此数据库连接上的所有表(或集合)加的前缀。
|
||||
|
||||
- `dropSchema` - 每次建立连接时删除架构。请注意此选项,不要在生产环境中使用它,否则将丢失所有生产数据。但是此选项在调试和开发期间非常有用。
|
||||
|
||||
- `synchronize` - 指示是否在每次应用程序启动时自动创建数据库架构。
|
||||
请注意此选项,不要在生产环境中使用它,否则将丢失所有生产数据。但是此选项在调试和开发期间非常有用。作为替代方案,你可以使用 CLI 运行 schema:sync 命令。请注意,对于 MongoDB 数据库,它不会创建模式,因为 MongoDB 是无模式的。相反,它只是通过创建索引来同步。
|
||||
|
||||
- `migrationsRun` - 指示是否在每次启动应用程序时自动运行迁移。或者,您可以使用 CLI run migrations:run command
|
||||
|
||||
- `migrationsTableName` - 数据库中将包含有关已执行迁移的信息的表的名称。默认情况下,此表名为"migrations"。
|
||||
|
||||
- `cache` - 启用实体结果缓存。你还可以在此处配置缓存类型和其他缓存选项。阅读更多有关[caching](./caching.md)的信息。
|
||||
|
||||
- `cli.entitiesDir` - CLI 默认情况下创建实体的目录。
|
||||
|
||||
- `cli.migrationsDir` - CLI 默认情况下创建迁移的目录。
|
||||
|
||||
- `cli.subscribersDir` - CLI 默认情况下创建订阅者的目录。
|
||||
|
||||
## `mysql`/`mariadb`
|
||||
|
||||
- `url` - 连接 URL
|
||||
|
||||
- `host` - 数据库 host
|
||||
|
||||
- `port` - 数据库端口。mysql 默认的端口是`3306`.
|
||||
|
||||
- `username` - 数据库用户名
|
||||
|
||||
- `password` - 数据库密码
|
||||
|
||||
- `database` - 数据库名
|
||||
|
||||
- `charset` - 连接的字符集。这在 MySQL 的 SQL 级别中称为"collation"(如 utf8_general_ci)。如果指定了 SQL 级别的字符集(如 utf8mb4),则使用该字符集的默认排序规则。 (默认值:UTF8_GENERAL_CI)。
|
||||
|
||||
- `timezone` - MySQL 服务器上配置的时区。这用于将服务器日期/时间值强制转换为 JavaScript Date 对象,反之亦然。该值可以是`local`,`Z`或`+HHMM`或`-HHMM`形式的偏移。 (默认:`local`)
|
||||
|
||||
- `connectTimeout` - 在连接到 MySQL 服务器期间发生超时之前的毫秒数。 (默认值:`10000`)
|
||||
|
||||
- `insecureAuth` - 允许连接到要求旧(不安全)身份验证方法的 MySQL 实例。 (默认值:`false`)
|
||||
|
||||
- `supportBigNumbers` - 处理数据库中的大数字(`BIGINT`和`DECIMAL`列)时,应启用此选项(默认值:`false`)
|
||||
|
||||
- `bigNumberStrings` - 同时启用`supportBigNumbers`和`bigNumberStrings`会强制将大数字(`BIGINT`和`DECIMAL`列)作为 JavaScript String 对象返回(默认值:`false`)。启用`supportBigNumbers`但禁用`bigNumberStrings`仅当它们无法用 JavaScript Number 对象准确表示时才会返回大数字作为 String 对象(当它们超过`[-2^53,+2^53]`范围时会发生),否则它们将被返回作为数字对象。如果禁用了`supportBigNumbers`,则忽略此选项。
|
||||
|
||||
- `dateStrings` - 强制日期类型(`TIMESTAMP`,`DATETIME`,`DATE`)作为字符串返回,而不是转换为 JavaScript Date 对象。可以是 true/false 或要保留为字符串的类型名称数组。 (默认值:`false`)
|
||||
|
||||
- `debug` - 将协议详细信息打印到 stdout。可以是 true/false 或应打印的数据包类型名称数组。 (默认值:`false`)
|
||||
|
||||
- `trace` - 在 Error 上生成堆栈跟踪,包括库入口的调用站点("long stack traces")。对大多调用来说,性能损失很轻。 (默认值:`true`)
|
||||
|
||||
- `multipleStatements` - 每个查询允许多个 mysql 语句。请注意,它可能会增加 SQL 注入攻击的范围。 (默认值:`false`)
|
||||
|
||||
- `legacySpatialSupport` - Use spatial functions like GeomFromText and AsText which are removed in MySQL 8. (Default: true)
|
||||
|
||||
- `flags` - 使用非默认连接标志的连接标志列表。也可以将默认值列入黑名单。有关更多信息,请查看[Connection Flags](https://github.com/mysqljs/mysql#connection-flags)。
|
||||
|
||||
- `ssl` - 带有 ssl 参数的对象或包含 ssl 配置文件名称的字符串。请参阅[SSL 选项](https://github.com/mysqljs/mysql#ssl-options)。
|
||||
|
||||
## `postgres`/`cockroachdb`连接选项
|
||||
|
||||
- `url` - 连接 URL
|
||||
|
||||
- `host` - 数据库主机
|
||||
|
||||
- `port` - 数据库端口, postgres 默认端口是 `5432`。
|
||||
|
||||
- `username` - 数据库用户名
|
||||
|
||||
- `password` - 数据库密码
|
||||
|
||||
- `database` - 数据库名称
|
||||
|
||||
- `schema` - Schema 名称,默认是 "public".
|
||||
|
||||
- `ssl` - 带有 ssl 参数的对象。 详见 [TLS/SSL](https://node-postgres.com/features/ssl)。
|
||||
|
||||
- `uuidExtension` - 生成UUID时使用的Postgres扩展。 默认为`uuid-ossp`。 如果`uuid-ossp`扩展不可用,可以更改为`pgcrypto`。
|
||||
|
||||
## `sqlite`
|
||||
|
||||
- `database` - 数据库路径。 例如 "./mydb.sql"
|
||||
|
||||
## `better-sqlite3`
|
||||
|
||||
* `database` - 数据库路径。 例如 "./mydb.sql"
|
||||
|
||||
* `statementCacheSize` - Sqlite 查询 Statement 缓存大小。默认100
|
||||
|
||||
* `prepareDatabase` - 在数据库投入使用前运行的函数。你可以在这里访问到better-sqlite3原始数据库对象。
|
||||
|
||||
## `cordova`
|
||||
|
||||
- `database` - 数据库名
|
||||
|
||||
- `location` - 数据库存储位置。 详见 [cordova-sqlite-storage](https://github.com/litehelpers/Cordova-sqlite-storage#opening-a-database)。
|
||||
|
||||
## `react-native`
|
||||
|
||||
- `database` - 数据库名
|
||||
|
||||
- `location` - 数据库存储位置。详见 [react-native-sqlite-storage](https://github.com/andpor/react-native-sqlite-storage#opening-a-database) 。
|
||||
|
||||
## `nativescript`
|
||||
|
||||
- `database` - 数据库名
|
||||
|
||||
## `mssql`
|
||||
|
||||
- `url` - 连接 URL
|
||||
|
||||
- `host` - 数据库主机
|
||||
|
||||
- `port` - 端口。mssql 默认端口是 `1433`.
|
||||
|
||||
- `username` - 用户名
|
||||
|
||||
- `password` - 密码
|
||||
|
||||
- `database` - 数据库名
|
||||
|
||||
- `schema` - Schema 名称。 默认"public".
|
||||
|
||||
- `domain` - 设置 domain 后,驱动程序将使用 domain 登录连接到 SQL Server。
|
||||
|
||||
- `connectionTimeout` - 超时时间,毫秒为单位 (默认: `15000`)。
|
||||
|
||||
- `requestTimeout` - 请求超时时间,毫秒为单位 (默认: `15000`)。注意: msnodesqlv8 驱动不支持
|
||||
timeouts < 1 秒
|
||||
|
||||
- `stream` - Stream recordsets/rows instead of returning them all at once as an argument of callback(默认值:`false`)。你还可以单独为每个请求启用 streaming(`request.stream = true`)。如果你计划使用大量 rows,请始终设置为`true`。
|
||||
|
||||
- `pool.max` - 连接池的最大数 (默认: `10`).
|
||||
|
||||
- `pool.min` - 连接池的最小数 (默认: `0`).
|
||||
|
||||
- `pool.maxWaitingClients` - 允许的最大队列请求数,在事件循环的未来周期中,将使用错误回调其他获取调用。
|
||||
|
||||
- `pool.testOnBorrow` - 如果连接池在将资源提供给客户端之前验证资源。需要指定`factory.validate`或`factory.validateAsync`。
|
||||
|
||||
- `pool.acquireTimeoutMillis` - 最大毫秒,`acquire`调用将在超时之前等待资源。(默认无限制),如果提供的话应该是非零正整数。
|
||||
|
||||
- `pool.fifo` - 如果为true,则首先分配最旧的资源。 如果为false,则表示最近发布的资源将是第一个被分配的。这实际上将池的行为从队列转换为堆栈。布尔值,(默认为`true`)。
|
||||
|
||||
- `pool.priorityRange` - 1和x之间的int值 - 如果设置了且没有可用资源,则borrowers可以在队列中指定其相对优先级(默认 `1`)。
|
||||
|
||||
- `pool.victionRunIntervalMillis` - 多久检查一次eviction checks。 默认值:`0`(不运行)。
|
||||
|
||||
- `pool.numTestsPerRun` - 每次eviction checks资源数量。 默认值:`3`。
|
||||
|
||||
- `pool.softIdleTimeoutMillis` - 在空闲对象逐出器(如果有的话)有资格驱逐之前,对象可以在池中空闲的时间量,其中额外条件是至少"最小空闲"对象实例保留在池中。默认 `-1` (nothing can get evicted).
|
||||
|
||||
- `pool.idleTimeoutMillis` - 对象在由于空闲时间而有资格被驱逐之前可能在池中闲置的最短时间。 取代`softIdleTimeoutMillis`。 默认值:`30000`。
|
||||
|
||||
- `options.fallbackToDefaultDb` - 默认情况下,如果无法访问`options.database`的数据库请求,则连接将失败并显示错误。 但是,如果`options.fallbackToDefaultDb`设置为`true`,则将改为使用用户的默认数据库(默认值:`false`)。
|
||||
|
||||
- `options.enableAnsiNullDefault` - 如果为true,则在初始sql中设置SET ANSI_NULL_DFLT_ON ON。 这意味着默认情况下新列可以为空。 有关更多详细信息,请参阅[T-SQL文档](https://msdn.microsoft.com/en-us/library/ms187375.aspx)。 (默认值:`true`)。
|
||||
|
||||
- `options.cancelTimeout` - 取消(中止)请求之前的毫秒数被视为失败(默认值:`5000`)。
|
||||
|
||||
- `options.packetSize` - TDS数据包的大小(需要与服务器协商)。 应该是2的幂。(默认值:`4096`)。
|
||||
|
||||
- `options.useUTC` - 布尔值,用于确定是以UTC还是本地时间。(默认:`false`)。
|
||||
|
||||
- `options.abortTransactionOnError` - 如果在给定事务执行期间遇到任何错误,则确定是否自动回滚事务的布尔值。 这将在连接的初始SQL阶段设置`SET XACT_ABORT`的值([文档](http://msdn.microsoft.com/en-us/library/ms188792.aspx))。
|
||||
|
||||
- `options.localAddress` - 字符串,指示连接到SQL Server时要使用的网络接口(IP地址)。
|
||||
|
||||
- `options.useColumnNames` - 布尔值,用于确定是将行作为数组还是键值集合返回。 (默认:`false`)。
|
||||
|
||||
- `options.camelCaseColumns` - 布尔值,控制返回的列名是否将第一个字母转换为小写(`true`为小写)。 如果提供`columnNameReplacer`,则忽略该值。 (默认:`false`)。
|
||||
|
||||
- `options.isolationLevel` - 将运行事务的默认隔离级别。 隔离级别可从`require('tedious').ISOLATION_LEVEL`获得。
|
||||
|
||||
- `READ_UNCOMMITTED`
|
||||
- `READ_COMMITTED`
|
||||
- `REPEATABLE_READ`
|
||||
- `SERIALIZABLE`
|
||||
- `SNAPSHOT`
|
||||
|
||||
(默认: `READ_COMMITTED`)
|
||||
|
||||
- `options.connectionIsolationLevel` - 新连接的默认隔离级别。 使用此设置执行所有事务外查询。 隔离级别可从`require('tedious').ISOLATION_LEVEL`获得。
|
||||
|
||||
- `READ_UNCOMMITTED`
|
||||
- `READ_COMMITTED`
|
||||
- `REPEATABLE_READ`
|
||||
- `SERIALIZABLE`
|
||||
- `SNAPSHOT`
|
||||
|
||||
(默认: `READ_COMMITTED`)
|
||||
|
||||
- `options.readOnlyIntent` - 布尔值,确定连接是否将从SQL Server可用性组请求只读访问权限。 有关更多信息,请参阅此处。 (默认:`false`)。
|
||||
|
||||
- `options.encrypt` - 确定连接是否将被加密的布尔值。 如果您使用的是Windows Azure,请设置为true。 (默认:`true`)。
|
||||
|
||||
- `options.cryptoCredentialsDetails` - 使用加密时,可以提供一个对象,该对象在调用[tls.createSecurePair](http://nodejs.org/docs/latest/api/tls.html#tls_tls_createsecurepair_credentials_isserver_requestcert_rejectunauthorized)时将用于第一个参数(默认值:`{}`)。
|
||||
|
||||
- `options.rowCollectionOnDone` - 布尔值,当为true时将在Requests的`done *`事件中公开接收到的行。
|
||||
查看 done, [doneInProc](http://tediousjs.github.io/tedious/api-request.html#event_doneInProc)
|
||||
和 [doneProc](http://tediousjs.github.io/tedious/api-request.html#event_doneProc). (默认: `false`)
|
||||
|
||||
注意:如果收到很多行,启用此选项可能会导致内存使用过多。
|
||||
|
||||
- `options.rowCollectionOnRequestCompletion` - 布尔值,当为true时将在请求的完成回调中公开接收的行。 查看 [new Request](http://tediousjs.github.io/tedious/api-request.html#function_newRequest). (默认: `false`)
|
||||
|
||||
注意:如果收到很多行,启用此选项可能会导致内存使用过多。
|
||||
|
||||
- `options.tdsVersion` - 要使用的TDS版本。 如果服务器不支持指定的版本,则使用协商的版本。 这些版本可以从`require('tedious').TDS_VERSION`获得。
|
||||
|
||||
- `7_1`
|
||||
- `7_2`
|
||||
- `7_3_A`
|
||||
- `7_3_B`
|
||||
- `7_4`
|
||||
|
||||
(默认: `7_4`)
|
||||
|
||||
- `options.debug.packet` - 布尔值,控制是否将使用描述数据包详细信息的文本发出`debug`事件(默认值:`false`)。
|
||||
|
||||
- `options.debug.data` - 布尔值,控制是否将发出`debug`事件,文本描述包数据细节(默认值:`false`)。
|
||||
|
||||
- `options.debug.payload` - 布尔值,控制是否使用描述数据包有效负载详细信息的文本发出`debug`事件(默认值:`false`)。
|
||||
|
||||
- `options.debug.token` - 布尔值,控制是否将使用描述令牌流令牌的文本发出`debug`事件(默认值:`false`)。
|
||||
|
||||
> 注: 由于译者对mssql理解不够深入,故一些翻译直接使用了机翻,因此会有些词不达意,如有更好的翻译选项,请提交PR进行完善。
|
||||
|
||||
## `mongodb`
|
||||
|
||||
- `url` - 连接 URL
|
||||
|
||||
- `host` - 数据库主机
|
||||
|
||||
- `port` - 端口号,mongodb 默认端口是`27017`
|
||||
|
||||
- `database` - 数据库名
|
||||
|
||||
- `poolSize` - 设置每个服务器或代理连接的最大池大小
|
||||
|
||||
- `ssl` - 使用 ssl 连接(需要有支持 ssl 的 mongod 服务器)。默认值:`false`。
|
||||
|
||||
- `sslValidate` - 针对 ca 验证 mongod 服务器证书(需要具有 ssl 支持的,2.4 或更高版本的 mongod 服务器)。默认值:`true`。
|
||||
|
||||
- `sslCA` - 有效证书的数组,可以是 Buffers 或 Strings(需要具有支持 ssl 的,2.4 或更高版本的 mongod 服务器)。
|
||||
|
||||
- `sslCert` - 包含我们希望提供的证书的字符串或缓冲区(需要具有支持 ssl 的,2.4 或更高版本的 mongod 服务器)。
|
||||
|
||||
- `sslKey` - String or buffer containing the certificate private key we wish to present (需要具有支持 ssl 的,2.4 或更高版本的 mongod 服务器)。
|
||||
|
||||
- `sslPass` - 包含我们希望提供的证书私钥的字符串或缓冲区 (needs to have a mongod server with ssl support,
|
||||
2.4 or higher).
|
||||
|
||||
- `autoReconnect` - 出错时重新连接。 默认: `true`.
|
||||
|
||||
- `noDelay` - TCP Socket NoDelay 选项. 默认: `true`.
|
||||
|
||||
- `keepAlive` - 在 TCP socket 上启动 keepAlive 之前等待的毫秒数。默认: `30000`.
|
||||
|
||||
- `connectTimeoutMS` - TCP 连接超时。 默认: `30000`.
|
||||
|
||||
- `socketTimeoutMS` - TCP Socket 连接超时。 默认: `360000`.
|
||||
|
||||
- `reconnectTries` - 服务器尝试重新连接 #次数. 默认: `30`.
|
||||
|
||||
- `reconnectInterval` - 服务器将在重试之间等待 #毫秒 默认: `1000`.
|
||||
|
||||
- `ha` - 打开高可用性监控。默认: `true`.
|
||||
|
||||
- `haInterval` - 每次复制状态检查之间的时间。 默认: `10000,5000`.
|
||||
|
||||
- `replicaSet` - 要连接的 replicaset 的名称。
|
||||
|
||||
- `acceptableLatencyMS` - 设置使用 NEAREST 时要选择的服务器范围(最低 ping ms +延迟时间范围,例如:范围为 1 到(1 + 15)ms)。默认值:15。
|
||||
|
||||
- `secondaryAcceptableLatencyMS` - 设置使用 NEAREST 时要选择的服务器范围(最低 ping ms +延迟时间范围,例如:范围为 1 到(1 + 15)ms)。默认值:15。
|
||||
|
||||
- `connectWithNoPrimary` - 设置驱动程序是否应该连接,即使没有主数据库依然可用。默认: `false`.
|
||||
|
||||
- `authSource` - 数据库身份验证是否依赖于另一个 databaseName。
|
||||
|
||||
- `w` - The write concern.
|
||||
|
||||
- `wtimeout` - The write concern 超时
|
||||
|
||||
- `j` - Specify a journal write concern. 默认: `false`.
|
||||
|
||||
- `forceServerObjectId` - 强制服务器分配\_id值而不是驱动程序。 默认: `false`.
|
||||
|
||||
- `serializeFunctions` - 序列化任何对象上的函数。 默认: `false`.
|
||||
|
||||
- `ignoreUndefined` - 指定BSON序列化程序是否应忽略未定义的字段。 默认: `false`.
|
||||
|
||||
- `raw` - 将文档结果作为原始BSON缓冲区返回。 默认: `false`.
|
||||
|
||||
- `promoteLongs` - 如果Long值适合53位分辨率,则将其提升为数字。默认: `true`.
|
||||
|
||||
- `promoteBuffers` - 将二进制BSON值提升为native Node Buffers。默认: `false`.
|
||||
|
||||
- `promoteValues` - 在可能的情况下将BSON值提升为native类型,设置为false以仅接收wrapper类型。默认: `true`.
|
||||
|
||||
- `domainsEnabled` - 启用当前域中回调的包装,默认情况下禁用以避免执行命中。 默认: `false`.
|
||||
|
||||
- `bufferMaxEntries` - 设置一个限制,在放弃获得有效连接之前,驱动程序将缓冲多少个操作,默认为-1标识无限制。
|
||||
|
||||
- `readPreference` - 首选read偏好:
|
||||
|
||||
- `ReadPreference.PRIMARY`
|
||||
- `ReadPreference.PRIMARY_PREFERRED`
|
||||
- `ReadPreference.SECONDARY`
|
||||
- `ReadPreference.SECONDARY_PREFERRED`
|
||||
- `ReadPreference.NEAREST`
|
||||
|
||||
- `pkFactory` - 用于生成自定义\_id键的主键工厂对象。
|
||||
|
||||
- `promiseLibrary` - 应用程序希望使用的Promise库类如Bluebird,必须与ES6兼容。
|
||||
|
||||
- `readConcern` - 指定集合的读取问题。 (仅支持MongoDB 3.2或更高版本)。
|
||||
|
||||
- `maxStalenessSeconds` - 为辅助读取指定maxStalenessSeconds值,最小值为90秒。
|
||||
|
||||
- `appname` - 创建此MongoClient实例的应用程序的名称。 MongoDB 3.4及更新版将在建立每个连接时在服务器日志中打印此值。它还记录在慢查询日志和概要文件集合中。
|
||||
|
||||
- `loggerLevel` - 指定驱动程序记录器使用的日志级别 (`error/warn/info/debug`)。
|
||||
|
||||
- `logger` - 指定客户记录器机制,可用于使用你的应用程序级别记录器进行记录。
|
||||
|
||||
- `authMechanism` - 设置MongoDB用于验证连接的身份验证机制。
|
||||
|
||||
- `directConnection` - 指定是否强制将所有操作分派到指定的主机。
|
||||
|
||||
> 注: 由于译者对MongoDB理解不够深入,故一些翻译直接使用了机翻,因此会有些词不达意,如有更好的翻译选项,请提交PR进行完善。
|
||||
|
||||
## `sql.js`
|
||||
|
||||
- `database`: 应导入的原始 UInt8Array 数据库。
|
||||
|
||||
- `sqlJsConfig`: sql.js可选启动配置
|
||||
|
||||
- `autoSave`: 是否应禁用 autoSave。如果设置为 true,则在发生更改并指定`location`时,数据库将保存到给定的文件位置(Node.js)或 LocalStorage(浏览器)。否则可以使用`autoSaveCallback`。
|
||||
|
||||
- `autoSaveCallback`: 在对数据库进行更改并启用`autoSave`时调用的函数。该函数获取表示数据库的`UInt8Array`。
|
||||
|
||||
- `location`: 要加载和保存数据库的文件位置。
|
||||
|
||||
- `useLocalForage`: 允许使用localforage库(https://github.com/localForage/localForage)从indexedDB异步保存和加载数据库,而不是在浏览器环境中使用synchron本地存储方法。 需要将localforage模块添加到项目中,并且应在页面中导入localforage.js。
|
||||
|
||||
## `expo`
|
||||
|
||||
- `database` - 数据库名, 例如 "mydb".
|
||||
- `driver` - Expo SQLite 模块. 例如,`require('expo-sqlite')`.
|
||||
|
||||
## 连接选项示例
|
||||
|
||||
以下是 mysql 连接选项的一个小例子:
|
||||
|
||||
```typescript
|
||||
{
|
||||
host: "localhost",
|
||||
port: 3306,
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test",
|
||||
logging: true,
|
||||
synchronize: true,
|
||||
entities: [
|
||||
"entity/*.js"
|
||||
],
|
||||
subscribers: [
|
||||
"subscriber/*.js"
|
||||
],
|
||||
entitySchemas: [
|
||||
"schema/*.json"
|
||||
],
|
||||
migrations: [
|
||||
"migration/*.js"
|
||||
]
|
||||
}
|
||||
```
|
||||
@ -1,68 +0,0 @@
|
||||
# 自定义存储库
|
||||
|
||||
你可以创建一个自定义存储库,其中应包含使用数据库的方法。
|
||||
通常为单个实体创建自定义存储库,并包含其特定查询。
|
||||
比如,假设我们想要一个名为`findByName(firstName:string,lastName:string)`的方法,它将按给定的 first 和 last names 搜索用户。
|
||||
这个方法的最好的地方是在`Repository`,所以我们可以这样称呼它`userRepository.findByName(...)`。
|
||||
你也可以使用自定义存储库来实现此目的。
|
||||
|
||||
有几种方法可以创建自定义存储库。
|
||||
|
||||
- [自定义存储库](#自定义存储库)
|
||||
- [如何自定义存储库](#如何自定义存储库)
|
||||
- [在事务中使用自定义存储库](#在事务中使用自定义存储库)
|
||||
|
||||
## 如何自定义存储库
|
||||
|
||||
常见的做法是将一个实体的存储库实例赋值给一个变量导出,然后在你的应用中使用它,例如:
|
||||
|
||||
```ts
|
||||
// user.repository.ts
|
||||
export const UserRepository = dataSource.getRepository(User)
|
||||
|
||||
// user.controller.ts
|
||||
export class UserController {
|
||||
users() {
|
||||
return UserRepository.find()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
你可以使用 `Repository` 类中的 `.extend` 方法来扩展 `UserRepository` 的功能:
|
||||
|
||||
```typescript
|
||||
// user.repository.ts
|
||||
export const UserRepository = dataSource.getRepository(User).extend({
|
||||
findByName(firstName: string, lastName: string) {
|
||||
return this.createQueryBuilder("user")
|
||||
.where("user.firstName = :firstName", { firstName })
|
||||
.andWhere("user.lastName = :lastName", { lastName })
|
||||
.getMany()
|
||||
},
|
||||
})
|
||||
|
||||
// user.controller.ts
|
||||
export class UserController {
|
||||
users() {
|
||||
return UserRepository.findByName("Timber", "Saw")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 在事务中使用自定义存储库
|
||||
|
||||
每个事务有自己的执行作用域:它们有自己的执行器、实体管理器和储存库。
|
||||
这就是使用全局的(数据源的)实体管理器和存储库在事务中并不会生效的原因。
|
||||
为了确保事务中的操作能够正确地被执行你**必须**使用提供的实体管理器实例及其 `getRepository` 方法。如果需要在事务中使用自定义存储库,你必须使用其提供的实体管理器实例上的 `withRepository` 方法:
|
||||
|
||||
```typescript
|
||||
await connection.transaction(async (manager) => {
|
||||
// 在事务中你必须使用其提供的实体管理器实例,
|
||||
// 不能使用全局的实体管理器或者存储库,
|
||||
// 因为这个实体管理器具有排他性和事务性
|
||||
|
||||
const userRepository = manager.withRepository(UserRepository)
|
||||
await userRepository.createAndSave("Timber", "Saw")
|
||||
const timber = await userRepository.findByName("Timber", "Saw")
|
||||
})
|
||||
```
|
||||
@ -1,339 +0,0 @@
|
||||
# Connection API
|
||||
|
||||
* [Main API](#main-api)
|
||||
* [`Connection` API](#connection-api-1)
|
||||
* [`ConnectionManager` API](#connectionmanager-api)
|
||||
|
||||
## Main API
|
||||
|
||||
* `createConnection()` - 创建一个新连接并将其注册到全局连接管理器中。
|
||||
如果省略connection options参数,则从`ormconfig`文件或环境变量中读取连接选项。
|
||||
|
||||
```typescript
|
||||
import {createConnection} from "typeorm";
|
||||
|
||||
const connection = await createConnection({
|
||||
type: "mysql",
|
||||
host: "localhost",
|
||||
port: 3306,
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test"
|
||||
});
|
||||
```
|
||||
|
||||
* `createConnections()` - 创建多个连接并在全局连接管理器中注册它们。
|
||||
如果省略connection options参数,则从`ormconfig`文件或环境变量中读取连接选项。
|
||||
|
||||
```typescript
|
||||
import {createConnections} from "typeorm";
|
||||
|
||||
const connection = await createConnections([{
|
||||
name: "connection1",
|
||||
type: "mysql",
|
||||
host: "localhost",
|
||||
port: 3306,
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test"
|
||||
}, {
|
||||
name: "connection2",
|
||||
type: "mysql",
|
||||
host: "localhost",
|
||||
port: 3306,
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test"
|
||||
}]);
|
||||
```
|
||||
|
||||
* `getConnectionManager()` - 获取存储所有已创建(使用`createConnection()`或`createConnections()`)连接的管理器。
|
||||
|
||||
```typescript
|
||||
import {getConnectionManager} from "typeorm";
|
||||
|
||||
const defaultConnection = getConnectionManager().get("default");
|
||||
const secondaryConnection = getConnectionManager().get("secondary");
|
||||
```
|
||||
|
||||
* `getConnection()` - 获取使用`createConnection`方法创建的连接。
|
||||
|
||||
```typescript
|
||||
import {getConnection} from "typeorm";
|
||||
|
||||
const connection = getConnection();
|
||||
// 如果有命名连接,则可以指定其名称:
|
||||
const secondaryConnection = getConnection("secondary-connection");
|
||||
```
|
||||
|
||||
* `getEntityManager()` - 获取`EntityManager`。
|
||||
可以指定连接名称以指示应该采用哪个连接的实体管理器。
|
||||
|
||||
```typescript
|
||||
import {getEntityManager} from "typeorm";
|
||||
|
||||
const manager = getEntityManager();
|
||||
// you can use manager methods now
|
||||
|
||||
const secondaryManager = getEntityManager("secondary-connection");
|
||||
// you can use secondary connection manager methods
|
||||
```
|
||||
|
||||
* `getRepository()` - Gets `Repository` for given entity from connection.
|
||||
可以指定连接名称以指示应该采用哪个连接的实体管理器。
|
||||
|
||||
```typescript
|
||||
import {getRepository} from "typeorm";
|
||||
|
||||
const userRepository = getRepository(User);
|
||||
// you can use repository methods now
|
||||
|
||||
const blogRepository = getRepository(Blog, "secondary-connection");
|
||||
// you can use secondary connection repository methods
|
||||
```
|
||||
|
||||
* `getTreeRepository()` - Gets `TreeRepository` for given entity from connection.
|
||||
可以指定连接名称以指示应该采用哪个连接的实体管理器。
|
||||
|
||||
```typescript
|
||||
import {getTreeRepository} from "typeorm";
|
||||
|
||||
const userRepository = getTreeRepository(User);
|
||||
// 使用存储库方法
|
||||
|
||||
const blogRepository = getTreeRepository(Blog, "secondary-connection");
|
||||
// 使用另一个存储库方法
|
||||
```
|
||||
|
||||
* `getMongoRepository()` - 获取给定实体的`MongoRepository`。
|
||||
可以指定连接名称以指示应该采用哪个连接的实体管理器。
|
||||
|
||||
```typescript
|
||||
import {getMongoRepository} from "typeorm";
|
||||
|
||||
const userRepository = getMongoRepository(User);
|
||||
//使用存储库方法
|
||||
|
||||
const blogRepository = getMongoRepository(Blog, "secondary-connection");
|
||||
// 使用另一个存储库方法
|
||||
```
|
||||
|
||||
## `Connection` API
|
||||
|
||||
* `name` - 连接名。 如果没有指定连接名,则默认值为`default`。
|
||||
在处理多个连接时使用此名称并调用`getConnection(connectionName:string)`。
|
||||
|
||||
```typescript
|
||||
const connectionName: string = connection.name;
|
||||
```
|
||||
|
||||
* `options` - 用于创建此连接的连接选项。
|
||||
了解有关[连接选项](./connection-options.md)的更多信息。
|
||||
|
||||
```typescript
|
||||
const connectionOptions: ConnectionOptions = connection.options;
|
||||
// 你可以将connectionOptions转换为MysqlConnectionOptions或任何其他xxxConnectionOptions,
|
||||
// 具体取决于你使用的数据库驱动程序
|
||||
```
|
||||
|
||||
* `isConnected` - 指示是否建立了与数据库的真实连接。
|
||||
|
||||
```typescript
|
||||
const isConnected: boolean = connection.isConnected;
|
||||
```
|
||||
|
||||
* `driver` - 此连接中使用的基础数据库驱动程序。
|
||||
|
||||
```typescript
|
||||
const driver: Driver = connection.driver;
|
||||
// 你可以根据使用的数据库驱动程序将connectionOptions转换为MysqlDriver或任何其他xxxDriver
|
||||
```
|
||||
|
||||
* `manager` - `EntityManager`用于连接实体。
|
||||
查看更多关于[实体管理器和存储库](working-with-entity-manager.md).
|
||||
|
||||
```typescript
|
||||
const manager: EntityManager = connection.manager;
|
||||
// 你可以调用manager方法,例如find:
|
||||
const user = await manager.findOne(1);
|
||||
```
|
||||
|
||||
* `mongoManager` - `MongoEntityManager`用于处理mongodb连接中的连接实体。
|
||||
有关MongoEntityManager的更多信息,请参阅[MongoDB](./mongodb.md)文档。
|
||||
|
||||
```typescript
|
||||
const manager: MongoEntityManager = connection.mongoManager;
|
||||
//你可以调用manager或mongodb-manager特定方法,例如find:
|
||||
const user = await manager.findOne(1);
|
||||
```
|
||||
|
||||
* `connect` - 执行与数据库的连接。
|
||||
当你使用`createConnection`时,它会自动调用`connect`,你不需要自己调用它。
|
||||
|
||||
```typescript
|
||||
await connection.connect();
|
||||
```
|
||||
|
||||
* `close` - 关闭与数据库的连接。
|
||||
通常需要在应用程序关闭时调用此方法。
|
||||
|
||||
```typescript
|
||||
await connection.close();
|
||||
```
|
||||
|
||||
* `synchronize` - 同步数据库架构。 当在连接选项中设置`synchronize:true`时,它会调用此方法。
|
||||
通常需要在应用程序关闭时调用此方法。
|
||||
|
||||
```typescript
|
||||
await connection.synchronize();
|
||||
```
|
||||
|
||||
* `dropDatabase` - 删除数据库及其所有数据。
|
||||
请谨慎使用此方法,因为此方法将清除所有数据库表及其数据。
|
||||
只有在建立与数据库的连接后才能使用。
|
||||
|
||||
```typescript
|
||||
await connection.dropDatabase();
|
||||
```
|
||||
|
||||
* `runMigrations` - 运行所有挂起的迁移。
|
||||
|
||||
```typescript
|
||||
await connection.runMigrations();
|
||||
```
|
||||
|
||||
* `undoLastMigration` - 恢复上次执行的迁移。
|
||||
|
||||
```typescript
|
||||
await connection.undoLastMigration();
|
||||
```
|
||||
|
||||
* `hasMetadata` - 检查是否已注册给定实体的元数据。
|
||||
了解更多关于 [Entity Metadata](./entity-metadata.md).
|
||||
|
||||
```typescript
|
||||
if (connection.hasMetadata(User))
|
||||
const userMetadata = connection.getMetadata(User);
|
||||
```
|
||||
|
||||
* `getMetadata` - 获取给定实体的`EntityMetadata`。
|
||||
你还可以指定表名,如果找到具有此类表名的实体元数据,则会返回该名称。
|
||||
了解更多关于 [Entity Metadata](./entity-metadata.md).
|
||||
|
||||
```typescript
|
||||
const userMetadata = connection.getMetadata(User);
|
||||
// 获得有关用户实体的任何信息
|
||||
```
|
||||
|
||||
* `getRepository` - 获取给定实体的`Repository`。
|
||||
你还可以指定表名,如果找到给定表的存储库,则会返回该表。
|
||||
了解更多关于 [Repositories](working-with-repository.md)。
|
||||
|
||||
```typescript
|
||||
const repository = connection.getRepository(User);
|
||||
// 调用存储库方法,例如find:
|
||||
const users = await repository.findOne(1);
|
||||
```
|
||||
|
||||
* `getTreeRepository` - Gets `TreeRepository` of the given entity.
|
||||
你还可以指定表名,如果找到给定表的存储库,则会返回该表。
|
||||
了解更多关于 [Repositories](working-with-repository.md)。
|
||||
|
||||
```typescript
|
||||
const repository = connection.getTreeRepository(Category);
|
||||
// 调用树存储库方法,例如findTrees:
|
||||
const categories = await repository.findTrees();
|
||||
```
|
||||
|
||||
* `getMongoRepository` -获取给定实体的`MongoRepository`。
|
||||
此存储库用于MongoDB连接中的实体。
|
||||
了解更多关于 [MongoDB support](./mongodb.md).
|
||||
|
||||
```typescript
|
||||
const repository = connection.getMongoRepository(User);
|
||||
// 调用特定于mongodb的存储库方法,例如createEntityCursor:
|
||||
const categoryCursor = repository.createEntityCursor();
|
||||
const category1 = await categoryCursor.next();
|
||||
const category2 = await categoryCursor.next();
|
||||
```
|
||||
|
||||
* `getCustomRepository` - 获取自定义的存储库。
|
||||
了解更多关于 [custom repositories](custom-repository.md)。
|
||||
|
||||
```typescript
|
||||
const userRepository = connection.getCustomRepository(UserRepository);
|
||||
// 调用自定义存储库中的方法 - UserRepository类
|
||||
const crazyUsers = await userRepository.findCrazyUsers();
|
||||
```
|
||||
|
||||
* `transaction` - 提供单个事务,在单个数据库事务中执行多个数据库请求。
|
||||
了解更多关于 [Transactions](./transactions.md).
|
||||
|
||||
```typescript
|
||||
await connection.transaction(async manager => {
|
||||
// 注意:你必须使用给定的管理器实例执行所有数据库操作,
|
||||
// 它是一个使用此事务的EntityManager的特殊实例,并且不要忘记在处理操作
|
||||
});
|
||||
```
|
||||
|
||||
* `query` - 执行原始SQL查询。
|
||||
|
||||
```typescript
|
||||
const rawData = await connection.query(`SELECT * FROM USERS`);
|
||||
```
|
||||
|
||||
* `createQueryBuilder` - 创建一个查询构建器,可用于构建查询。
|
||||
了解更多关于 [QueryBuilder](select-query-builder.md).
|
||||
|
||||
```typescript
|
||||
const users = await connection.createQueryBuilder()
|
||||
.select()
|
||||
.from(User, "user")
|
||||
.where("user.name = :name", { name: "John" })
|
||||
.getMany();
|
||||
```
|
||||
|
||||
* `createQueryRunner` - 创建一个用于管理和使用单个真实数据库连接的查询运行器。
|
||||
了解更多关于 [QueryRunner](./query-runner.md).
|
||||
|
||||
```typescript
|
||||
const queryRunner = connection.createQueryRunner();
|
||||
|
||||
// 只有在调用connect执行真正的数据库连接后才能使用它的方法
|
||||
await queryRunner.connect();
|
||||
|
||||
// .. 使用查询运行器并调用其方法
|
||||
|
||||
// 重要提示 - 一旦完成,不要忘记释放查询运行器
|
||||
await queryRunner.release();
|
||||
```
|
||||
|
||||
## `ConnectionManager` API
|
||||
|
||||
* `create` - 创建一个新连接并在管理器中注册。
|
||||
|
||||
```typescript
|
||||
const connection = connectionManager.create({
|
||||
type: "mysql",
|
||||
host: "localhost",
|
||||
port: 3306,
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test"
|
||||
});
|
||||
```
|
||||
|
||||
* `get` - 获取已经创建的连接存储在管理器中的名称。
|
||||
|
||||
```typescript
|
||||
const defaultConnection = connectionManager.get("default");
|
||||
const secondaryConnection = connectionManager.get("secondary");
|
||||
```
|
||||
|
||||
* `has` - 检查是否在给定的连接管理器中注册了连接。
|
||||
|
||||
```typescript
|
||||
if (connectionManager.has("default")) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
@ -1,185 +0,0 @@
|
||||
# 数据库连接
|
||||
|
||||
- [连接](#connection)
|
||||
- [什么是`Connection`](#什么是`Connection`)
|
||||
- [创建新的连接](#创建新的连接)
|
||||
- [使用`ConnectionManager`](#使用`ConnectionManager`)
|
||||
- [使用连接](#使用连接)
|
||||
|
||||
## 什么是`Connection`
|
||||
|
||||
只有在建立连接后才能与数据库进行交互。
|
||||
TypeORM 的`Connection`不会像看起来那样设置单个数据库连接,而是设置连接池。
|
||||
如果你对数据库连接感兴趣,请参阅`QueryRunner`文档。
|
||||
`QueryRunner`的每个实例都是一个独立的数据库连接。一旦调用`Connection`的`connect`方法,就建立连接池设置。
|
||||
如果使用`createConnection`函数设置连接,则会自动调用`connect`方法。调用`close`时会断开连接(关闭池中的所有连接)。
|
||||
通常情况下,你只能在应用程序启动时创建一次连接,并在完全使用数据库后关闭它。实际上,如果要为站点构建后端,并且后端服务器始终保持运行,则不需要关闭连接。
|
||||
|
||||
## 创建新的连接
|
||||
|
||||
有多种方法可以创建连接。但是最简单和最常用的方法是使用`createConnection`和`createConnections`函数。
|
||||
|
||||
`createConnection` 创建单个连接:
|
||||
|
||||
```typescript
|
||||
import { createConnection, Connection } from "typeorm"
|
||||
|
||||
const connection = await createConnection({
|
||||
type: "mysql",
|
||||
host: "localhost",
|
||||
port: 3306,
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test",
|
||||
})
|
||||
```
|
||||
|
||||
只使用`url`和`type`也可以进行连接。
|
||||
|
||||
```js
|
||||
createConnection({
|
||||
type: "postgres",
|
||||
url: "postgres://test:test@localhost/test",
|
||||
})
|
||||
```
|
||||
|
||||
`createConnections` 创建多个连接:
|
||||
|
||||
```typescript
|
||||
import { createConnections, Connection } from "typeorm"
|
||||
|
||||
const connections = await createConnections([
|
||||
{
|
||||
name: "default",
|
||||
type: "mysql",
|
||||
host: "localhost",
|
||||
port: 3306,
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test",
|
||||
},
|
||||
{
|
||||
name: "test2-connection",
|
||||
type: "mysql",
|
||||
host: "localhost",
|
||||
port: 3306,
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test2",
|
||||
},
|
||||
])
|
||||
```
|
||||
|
||||
这两种方式都根据你传递的连接选项创建`Connection`,并调用`connect`方法。另外你也可以在项目的根目录中创建一个`ormconfig.json`文件,`createConnection`和`createConnections`将自动从此文件中读取连接选项。项目的根目录与`node_modules`目录的级别相同。
|
||||
|
||||
```typescript
|
||||
import { createConnection, createConnections, Connection } from "typeorm"
|
||||
|
||||
// createConnection将从ormconfig.json / ormconfig.js / ormconfig.env 文件或特殊环境变量中加载连接选项
|
||||
const connection: Connection = await createConnection()
|
||||
|
||||
// 你可以指定要创建的连接的名称
|
||||
// (如果省略名称,则将创建没有指定名称的连接)
|
||||
const secondConnection: Connection = await createConnection("test2-connection")
|
||||
|
||||
// 如果调用createConnections而不是createConnection
|
||||
// 它将初始化并返回ormconfig文件中定义的所有连接
|
||||
const connections: Connection[] = await createConnections()
|
||||
```
|
||||
|
||||
不同的连接必须具有不同的名称。默认情况下,如果未指定连接名称,则为`default`。
|
||||
通常在你使用多个数据库或多个连接配置时才会使用多连接。
|
||||
|
||||
创建连接后,你可以使用`getConnection`函数从应用程序中的任何位置使用它:
|
||||
|
||||
```typescript
|
||||
import { getConnection } from "typeorm"
|
||||
|
||||
// 可以在调用createConnection后使用并解析
|
||||
const connection = getConnection()
|
||||
|
||||
// 如果你有多个连接,则可以按名称获取连接
|
||||
const secondConnection = getConnection("test2-connection")
|
||||
```
|
||||
|
||||
应避免额外创建 classes/services 来存储和管理连接。此功能已嵌入到 TypeORM 中 - 无需过度工程并创建无用的抽象。
|
||||
|
||||
## 使用`ConnectionManager`
|
||||
|
||||
你可以使用`ConnectionManager`类创建连接。例如:
|
||||
|
||||
```typescript
|
||||
import { getConnectionManager, ConnectionManager, Connection } from "typeorm"
|
||||
|
||||
const connectionManager = getConnectionManager()
|
||||
const connection = connectionManager.create({
|
||||
type: "mysql",
|
||||
host: "localhost",
|
||||
port: 3306,
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test",
|
||||
})
|
||||
await connection.connect() // 执行连接
|
||||
```
|
||||
|
||||
这不是常规创建连接的方法,但它可能对某些用户有用。例如,想要创建连接并存储其实例,同时控制何时建立实际"connection"。你还可以创建和维护自己的`ConnectionManager`:
|
||||
|
||||
```typescript
|
||||
import { getConnectionManager, ConnectionManager, Connection } from "typeorm"
|
||||
|
||||
const connectionManager = new ConnectionManager()
|
||||
const connection = connectionManager.create({
|
||||
type: "mysql",
|
||||
host: "localhost",
|
||||
port: 3306,
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test",
|
||||
})
|
||||
await connection.connect() // 执行连接
|
||||
```
|
||||
|
||||
但请注意,使用该方式,你将无法再使用`getConnection()` - 你需要存储连接管理器实例,并使用`connectionManager.get`来获取所需的连接。
|
||||
|
||||
通常情况下为避免应用程序中出现不必要的复杂情况,应尽量少使用此方法,除非你确实认为需要时才使用`ConnectionManager`。
|
||||
|
||||
## 使用连接
|
||||
|
||||
设置连接后,可以使用`getConnection`函数在应用程序的任何位置使用它:
|
||||
|
||||
```typescript
|
||||
import { getConnection } from "typeorm"
|
||||
import { User } from "../entity/User"
|
||||
|
||||
export class UserController {
|
||||
@Get("/users")
|
||||
getAll() {
|
||||
return getConnection().manager.find(User)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
你也可以使用`ConnectionManager#get`来获取连接,但在大多数情况下使用`getConnection()`就足够了。
|
||||
|
||||
使用 Connection,你可以对实体执行数据库操作,尤其是使用连接的`EntityManager`和`Repository`。
|
||||
有关它们的更多信息,请参阅[Entity Manager 和 Repository](working-with-entity-manager.md) 文档。
|
||||
|
||||
但一般来说,你不要太多使用`Connection`。大多数情况下,你只需创建连接并使用`getRepository()`和`getManager()`来访问连接的管理器和存储库,而无需直接使用连接对象:
|
||||
|
||||
```typescript
|
||||
import { getManager, getRepository } from "typeorm"
|
||||
import { User } from "../entity/User"
|
||||
|
||||
export class UserController {
|
||||
@Get("/users")
|
||||
getAll() {
|
||||
return getManager().find(User)
|
||||
}
|
||||
|
||||
@Get("/users/:id")
|
||||
getAll(@Param("id") userId: number) {
|
||||
return getRepository(User).findOne(userId)
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -1,882 +0,0 @@
|
||||
# 装饰器参考
|
||||
|
||||
* [实体装饰器](#实体装饰器)
|
||||
* [`@Entity`](#entity)
|
||||
* [`@ViewEntity`](#viewentity)
|
||||
* [列装饰器](#列装饰器)
|
||||
* [`@Column`](#column)
|
||||
* [`@PrimaryColumn`](#primarycolumn)
|
||||
* [`@PrimaryGeneratedColumn`](#primarygeneratedcolumn)
|
||||
* [`@ObjectIdColumn`](#objectidcolumn)
|
||||
* [`@CreateDateColumn`](#createdatecolumn)
|
||||
* [`@UpdateDateColumn`](#updatedatecolumn)
|
||||
* [`@VersionColumn`](#versioncolumn)
|
||||
* [`@Generated`](#generated)
|
||||
* [关系装饰器](#关系装饰器)
|
||||
* [`@OneToOne`](#onetoone)
|
||||
* [`@ManyToOne`](#manytoone)
|
||||
* [`@OneToMany`](#onetomany)
|
||||
* [`@ManyToMany`](#manytomany)
|
||||
* [`@JoinColumn`](#joincolumn)
|
||||
* [`@JoinTable`](#jointable)
|
||||
* [`@RelationId`](#relationid)
|
||||
* [订阅者和监听者装饰器](#订阅者和监听者装饰器)
|
||||
* [`@AfterLoad`](#afterload)
|
||||
* [`@BeforeInsert`](#beforeinsert)
|
||||
* [`@AfterInsert`](#afterinsert)
|
||||
* [`@BeforeUpdate`](#beforeupdate)
|
||||
* [`@AfterUpdate`](#afterupdate)
|
||||
* [`@BeforeRemove`](#beforeremove)
|
||||
* [`@AfterRemove`](#afterremove)
|
||||
* [`@BeforeSoftRemove`](#beforeremove)
|
||||
* [`@AfterSoftRemove`](#afterremove)
|
||||
* [`@BeforeRecover`](#beforeremove)
|
||||
* [`@AfterRecover`](#afterremove)
|
||||
* [`@EventSubscriber`](#eventsubscriber)
|
||||
* [其他装饰器](#其他装饰器)
|
||||
* [`@Index`](#index)
|
||||
* [`@Unique`](#unique)
|
||||
* [`@Check`](#check)
|
||||
* [`@Transaction`, `@TransactionManager` 和 `@TransactionRepository`](#transaction-transactionmanager-%E5%92%8C-transactionrepository)
|
||||
* [`@EntityRepository`](#entityrepository)
|
||||
|
||||
## 实体装饰器
|
||||
|
||||
#### `@Entity`
|
||||
|
||||
将模型标记为实体。 实体是一个转换为数据库表的类。
|
||||
你可以在实体中指定表名:
|
||||
|
||||
```typescript
|
||||
@Entity("users")
|
||||
export class User {
|
||||
```
|
||||
|
||||
此代码将创建一个名为"users"的数据库表。
|
||||
|
||||
你还可以指定一些其他实体选项:
|
||||
|
||||
- `name` - 表名。 如果未指定,则从实体类名生成表名。
|
||||
- `database` - 所选 DB 服务器中的数据库名称。
|
||||
- `schema` - 架构名称。
|
||||
- `engine` - 在表创建期间设置的数据库引擎(仅在某些数据库中有效)。
|
||||
- `synchronize` - 架构更新中跳过标有`false`的实体。
|
||||
- `skipSync` - 标有此装饰器的实体将从架构更新中跳过。
|
||||
- `orderBy` - 使用`find`操作和`QueryBuilder`指定实体的默认排序。
|
||||
|
||||
例子:
|
||||
|
||||
```typescript
|
||||
@Entity({
|
||||
name: "users",
|
||||
engine: "MyISAM",
|
||||
database: 'example_dev',
|
||||
schema: 'schema_with_best_tables',
|
||||
synchronize: false,
|
||||
orderBy: {
|
||||
name: "ASC",
|
||||
id: "DESC"
|
||||
}
|
||||
})
|
||||
export class User {
|
||||
```
|
||||
|
||||
了解有关 [Entities](entities.md)的更多信息。
|
||||
|
||||
#### `@ViewEntity`
|
||||
|
||||
视图实体是一个映射到数据库视图的类。
|
||||
|
||||
`@ViewEntity()` 接收以下参数:
|
||||
|
||||
* `name` - 视图名称。 如果未指定,则从实体类名生成视图名称。
|
||||
* `database` - 所选DB服务器中的数据库名称。
|
||||
* `schema` - 架构名称。
|
||||
* `expression` - 视图定义。 **必需参数**。
|
||||
|
||||
`expression`可以是带有正确转义的列和表的字符串,取决于所使用的数据库(示例中为postgres):
|
||||
|
||||
```typescript
|
||||
@ViewEntity({
|
||||
expression: `
|
||||
SELECT "post"."id" "id", "post"."name" AS "name", "category"."name" AS "categoryName"
|
||||
FROM "post" "post"
|
||||
LEFT JOIN "category" "category" ON "post"."categoryId" = "category"."id"
|
||||
`
|
||||
})
|
||||
export class PostCategory {
|
||||
```
|
||||
|
||||
或者是QueryBuilder的一个实例
|
||||
|
||||
```typescript
|
||||
@ViewEntity({
|
||||
expression: (connection: Connection) => connection.createQueryBuilder()
|
||||
.select("post.id", "id")
|
||||
.addSelect("post.name", "name")
|
||||
.addSelect("category.name", "categoryName")
|
||||
.from(Post, "post")
|
||||
.leftJoin(Category, "category", "category.id = post.categoryId")
|
||||
})
|
||||
export class PostCategory {
|
||||
```
|
||||
|
||||
**注意:** 由于驱动程序的限制,不支持参数绑定。请改用文字参数。
|
||||
|
||||
```typescript
|
||||
@ViewEntity({
|
||||
expression: (connection: Connection) => connection.createQueryBuilder()
|
||||
.select("post.id", "id")
|
||||
.addSelect("post.name", "name")
|
||||
.addSelect("category.name", "categoryName")
|
||||
.from(Post, "post")
|
||||
.leftJoin(Category, "category", "category.id = post.categoryId")
|
||||
.where("category.name = :name", { name: "Cars" }) // <-- 这是错的
|
||||
.where("category.name = 'Cars'") // <-- 这是对的
|
||||
})
|
||||
export class PostCategory {
|
||||
```
|
||||
|
||||
了解有关[View Entities](view-entities.md)的更多信息。
|
||||
|
||||
## 列装饰器
|
||||
|
||||
#### `@Column`
|
||||
|
||||
将实体中的属性标记为表列。
|
||||
例:
|
||||
|
||||
```typescript
|
||||
@Entity("users")
|
||||
export class User {
|
||||
@Column({ primary: true })
|
||||
id: number;
|
||||
|
||||
@Column({ type: "varchar", length: 200, unique: true })
|
||||
firstName: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
lastName: string;
|
||||
|
||||
@Column({ default: false })
|
||||
isActive: string;
|
||||
}
|
||||
```
|
||||
|
||||
`@Column` 接受可以使用的几个选项:
|
||||
|
||||
- `type: ColumnType` - 列类型。受支持的[supported column types](entities.md#column-types)其中之一。
|
||||
- `name: string` -数据库表中的列名。
|
||||
默认情况下,列名称是从属性的名称生成的。你也可以自定义命名。
|
||||
- `length: string|number` - 列类型的长度。 例如,如果要创建`varchar(150)`类型,请指定列类型和长度选项。
|
||||
- `width: number` - 列类型的显示宽度。 仅用于 [MySQL integer types](https://dev.mysql.com/doc/refman/5.7/en/integer-types.html)
|
||||
- `onUpdate: string` - `ON UPDATE` 触发器。仅用于 [MySQL](https://dev.mysql.com/doc/refman/5.7/en/timestamp-initialization.html).
|
||||
- `nullable: boolean` - 设置列值`NULL`或`NOT NULL`。
|
||||
默认值是 `nullable: false`。
|
||||
- `update: boolean` - 指示"save"操作是否更新列值。如果为false,则只能在第一次插入对象时编写该值。
|
||||
默认值为"true"。
|
||||
- `select: boolean` - 定义在进行查询时是否默认隐藏此列。 设置为`false`时,列数据不会显示标准查询。 默认值`select:true`。
|
||||
- `default: string` - 添加数据库级列的`DEFAULT`值。
|
||||
- `primary: boolean` - 将列标记为主列。 与`@PrimaryColumn`使用相同。
|
||||
- `unique: boolean` - 将列标记为唯一列(创建唯一约束)。
|
||||
- `comment: string` - 列的注释。 并非所有数据库类型都支持。
|
||||
- `precision: number` - 十进制(精确数字)列的精度(仅适用于十进制列),这是为值存储的最大位数。用于某些列类型。
|
||||
- `scale: number` - 十进制(精确数字)列的比例(仅适用于十进制列),表示小数点右侧的位数,且不得大于精度。用于某些列类型。
|
||||
- `zerofill: boolean` - 将`ZEROFILL`属性设置为数字列。 仅在 MySQL 中使用。
|
||||
如果是`true`,MySQL 会自动将`UNSIGNED`属性添加到此列。
|
||||
- `unsigned: boolean` - 将`UNSIGNED`属性设置为数字列。 仅在 MySQL 中使用。
|
||||
- `charset: string` - 定义列字符集。 并非所有数据库类型都支持。
|
||||
- `collation: string` - 定义列排序规则。
|
||||
- `enum: string[]|AnyEnum` - 在`enum`列类型中使用,以指定允许的枚举值列表。
|
||||
你可以指定值数组或指定枚举类。
|
||||
- `asExpression: string` - 生成的列表达式。 仅用于 [MySQL](https://dev.mysql.com/doc/refman/5.7/en/create-table-generated-columns.html).
|
||||
- `generatedType: "VIRTUAL"|"STORED"` - 生成的列类型。 仅用于 [MySQL](https://dev.mysql.com/doc/refman/5.7/en/create-table-generated-columns.html).
|
||||
- `hstoreType: "object"|"string"` - 返回类型`HSTORE`列。 以字符串或对象的形式返回值。 仅用于 [Postgres](https://www.postgresql.org/docs/9.6/static/hstore.html).
|
||||
- `array: boolean` - 用于可以是数组的 postgres 列类型(例如 int [])。
|
||||
- `transformer: ValueTransformer` - 指定在读取或写入数据库时用于封送/取消封送此列的值转换器。
|
||||
- `spatialFeatureType: string` - 可选的要素类型(`Point`,`Polygon`,`LineString`,`Geometry`)用作空间列的约束。 如果没有指定,默认为`Geometry`。 仅在 PostgreSQL 中使用。
|
||||
- `srid: number` - 可选的 [Spatial Reference ID](https://postgis.net/docs/using_postgis_dbmanagement.html#spatial_ref_sys) 用作空间列约束。如果未指定,则默认为`0`。 标准地理坐标(WGS84 基准面中的纬度/经度)对应于[EPSG 4326](http://spatialreference.org/ref/epsg/wgs-84/)。 仅在 PostgreSQL 中使用。
|
||||
|
||||
了解有关[entity columns](entities.md#entity-columns)的更多信息。
|
||||
|
||||
#### `@PrimaryColumn`
|
||||
|
||||
将实体中的属性标记为表主列。
|
||||
与`@column`装饰器相同,但需将其`primary`选项设置为 true。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class User {
|
||||
@PrimaryColumn()
|
||||
id: number;
|
||||
}
|
||||
```
|
||||
|
||||
了解有关 [entity columns](entities.md#entity-columns)的更多信息。
|
||||
|
||||
#### `@PrimaryGeneratedColumn`
|
||||
|
||||
将实体中的属性标记为表生成的主列。
|
||||
它创建的列是主列,值自动生成。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class User {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
}
|
||||
```
|
||||
|
||||
有两种策略:
|
||||
|
||||
- `increment` - 使用 AUTO_INCREMENT / SERIAL / SEQUENCE(取决于数据库类型)生成增量编号。
|
||||
- `uuid` - 生成唯一的`uuid`字符串。
|
||||
|
||||
默认生成策略是`increment`,将其更改为`uuid`,只需将其作为 decorator 的第一个参数传递:
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class User {
|
||||
@PrimaryGeneratedColumn("uuid")
|
||||
id: number;
|
||||
}
|
||||
```
|
||||
|
||||
了解有关[entity columns](entities.md#entity-columns)的更多信息。
|
||||
|
||||
#### `@ObjectIdColumn`
|
||||
|
||||
将实体中的属性标记为 ObjectID。
|
||||
此装饰器仅用于 MongoDB。
|
||||
MongoDB 中的每个实体都必须具有 ObjectID 列。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class User {
|
||||
@ObjectIdColumn()
|
||||
id: ObjectID;
|
||||
}
|
||||
```
|
||||
|
||||
了解有关[MongoDB](mongodb.md)的更多信息。
|
||||
|
||||
#### `@CreateDateColumn`
|
||||
|
||||
特殊列,自动设置为实体的插入时间。
|
||||
不需要在此列中手动写入值,该值会自动设置。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class User {
|
||||
@CreateDateColumn()
|
||||
createdDate: Date;
|
||||
}
|
||||
```
|
||||
|
||||
#### `@UpdateDateColumn`
|
||||
|
||||
每次从实体管理器或存储库调用`save`时自动设置为实体更新时间的特殊列。
|
||||
不需要在此列中手动写入值,该值会自动设置。
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class User {
|
||||
@UpdateDateColumn()
|
||||
updatedDate: Date;
|
||||
}
|
||||
```
|
||||
|
||||
#### `@VersionColumn`
|
||||
|
||||
每次从实体管理器或存储库调用`save`时自动设置为实体版本(增量编号)的特殊列。
|
||||
不需要在此列中手动写入值,该值会自动设置。
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class User {
|
||||
@VersionColumn()
|
||||
version: number;
|
||||
}
|
||||
```
|
||||
|
||||
#### `@Generated`
|
||||
|
||||
将列标记为生成的值。 例如:
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class User {
|
||||
@Column()
|
||||
@Generated("uuid")
|
||||
uuid: string;
|
||||
}
|
||||
```
|
||||
|
||||
在将实体插入数据库之前,只会生成一次值。
|
||||
|
||||
## 关系装饰器
|
||||
|
||||
#### `@OneToOne`
|
||||
|
||||
一对一是一种 A 只包含一次 B,而 B 只包含一个 A 的实例关系。
|
||||
我们以`User`和`Profile`实体为例。
|
||||
用户只能拥有一个 profile,并且一个 profile 仅由一个用户拥有。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
import { Entity, OneToOne, JoinColumn } from "typeorm";
|
||||
import { Profile } from "./Profile";
|
||||
|
||||
@Entity()
|
||||
export class User {
|
||||
@OneToOne(type => Profile, profile => profile.user)
|
||||
@JoinColumn()
|
||||
profile: Profile;
|
||||
}
|
||||
```
|
||||
|
||||
了解有关[一对一关系](one-to-one-relations.md)的更多信息。
|
||||
|
||||
#### `@ManyToOne`
|
||||
|
||||
多对一/一对多是 A 包含多个 B 实例,但 B 只包含一个 A 实例的关系。
|
||||
我们以`User`和`Photo`实体为例。
|
||||
User 可以拥有多张 photos,但每张 photo 仅由一位 user 拥有。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from "typeorm";
|
||||
import { User } from "./User";
|
||||
|
||||
@Entity()
|
||||
export class Photo {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
url: string;
|
||||
|
||||
@ManyToOne(type => User, user => user.photos)
|
||||
user: User;
|
||||
}
|
||||
```
|
||||
|
||||
了解有关[多对一/一对多关系](many-to-one-one-to-many-relations.md)的更多信息。
|
||||
|
||||
#### `@OneToMany`
|
||||
|
||||
多对一/一对多是 A 包含多个 B 实例,但 B 只包含一个 A 实例的关系。
|
||||
我们以`User`和`Photo`实体为例。
|
||||
User 可以拥有多张 photos,但每张 photo 仅由一位 user 拥有。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from "typeorm";
|
||||
import { Photo } from "./Photo";
|
||||
|
||||
@Entity()
|
||||
export class User {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@OneToMany(type => Photo, photo => photo.user)
|
||||
photos: Photo[];
|
||||
}
|
||||
```
|
||||
|
||||
了解有关 [多对一/一对多关系](many-to-one-one-to-many-relations.md)的更多信息。
|
||||
|
||||
#### `@ManyToMany`
|
||||
|
||||
多对多是一种 A 包含多个 B 实例,而 B 包含多个 A 实例的关系。
|
||||
我们以`Question`和`Category`实体为例。
|
||||
Question 可以有多个 categories,每个 category 可以有多个 questions。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
import { Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable } from "typeorm";
|
||||
import { Category } from "./Category";
|
||||
|
||||
@Entity()
|
||||
export class Question {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
title: string;
|
||||
|
||||
@Column()
|
||||
text: string;
|
||||
|
||||
@ManyToMany(type => Category)
|
||||
@JoinTable()
|
||||
categories: Category[];
|
||||
}
|
||||
```
|
||||
|
||||
了解有关 [多对多关系](many-to-many-relations.md)的更多信息。
|
||||
|
||||
#### `@JoinColumn`
|
||||
|
||||
定义关系的哪一侧包含具有外键和的联接列允许你自定义联接列名和引用列名。
|
||||
使用外键定义关系的哪一侧包含 join 列,并允许你自定义 join 列名称和引用的列名称。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class Post {
|
||||
@ManyToOne(type => Category)
|
||||
@JoinColumn({
|
||||
name: "cat_id",
|
||||
referencedColumnName: "name"
|
||||
})
|
||||
category: Category;
|
||||
}
|
||||
```
|
||||
|
||||
#### `@JoinTable`
|
||||
|
||||
用于`多对多`关系,并描述"junction"表的连接列。
|
||||
Junction 是由 TypeORM 自动创建的一个特殊的独立表,其中列引用了相关实体。
|
||||
|
||||
你可以使用`@JoinColumn`装饰器更改联结表及其引用列中的列名。 还可以更改生成的"junction"表的名称。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class Post {
|
||||
@ManyToMany(type => Category)
|
||||
@JoinTable({
|
||||
name: "question_categories",
|
||||
joinColumn: {
|
||||
name: "question",
|
||||
referencedColumnName: "id"
|
||||
},
|
||||
inverseJoinColumn: {
|
||||
name: "category",
|
||||
referencedColumnName: "id"
|
||||
}
|
||||
})
|
||||
categories: Category[];
|
||||
}
|
||||
```
|
||||
|
||||
如果目标表具有复合主键,则必须将一组属性发送到`@JoinTable`装饰器。
|
||||
|
||||
#### `@RelationId`
|
||||
|
||||
将特定关系的 id(或 id)加载到属性中。
|
||||
例如,如果你的`Post`实体中有一个多对一的`category`,你可以通过用`@RelationId`标记一个新属性来获得一个新的类别 id。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class Post {
|
||||
@ManyToOne(type => Category)
|
||||
category: Category;
|
||||
|
||||
@RelationId((post: Post) => post.category) // 需要指定目标关系
|
||||
categoryId: number;
|
||||
}
|
||||
```
|
||||
|
||||
此功能适用于所有类型的关系,包括`多对多`:
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class Post {
|
||||
@ManyToMany(type => Category)
|
||||
categories: Category[];
|
||||
|
||||
@RelationId((post: Post) => post.categories)
|
||||
categoryIds: number[];
|
||||
}
|
||||
```
|
||||
|
||||
Relation id 仅用于表现。
|
||||
链接值时,不会添加/删除/更改基础关系。
|
||||
|
||||
## 订阅者和监听者装饰器
|
||||
|
||||
#### `@AfterLoad`
|
||||
|
||||
你可以在实体中定义具有任何名称的方法,并使用`@AfterLoad`标记,TypeORM 将在每次使用`QueryBuilder`或 repository/ manager 查找方法加载时调用它。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class Post {
|
||||
@AfterLoad()
|
||||
updateCounters() {
|
||||
if (this.likesCount === undefined) this.likesCount = 0;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
了解有关[listeners](listeners-and-subscribers.md)的更多信息。
|
||||
|
||||
#### `@BeforeInsert`
|
||||
|
||||
你可以在实体中定义任何名称的方法,并使用`@BeforeInsert`标记,TypeORM 将在使用 repository/manager`save`插入实体之前调用它。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class Post {
|
||||
@BeforeInsert()
|
||||
updateDates() {
|
||||
this.createdDate = new Date();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
了解有关[listeners](listeners-and-subscribers.md)的更多信息。
|
||||
|
||||
#### `@AfterInsert`
|
||||
|
||||
你可以在实体中定义任何名称的方法,并使用`@AfterInsert`标记,TypeORM 将在使用 repository/manager`save`插入实体后调用它。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class Post {
|
||||
@AfterInsert()
|
||||
resetCounters() {
|
||||
this.counters = 0;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
了解有关 [listeners](listeners-and-subscribers.md)的更多信息。
|
||||
|
||||
#### `@BeforeUpdate`
|
||||
|
||||
你可以在实体中定义任何名称的方法,并使用`@BeforeUpdate`标记,TypeORM 将在使用 repository/manager`save`更新现有实体之前调用它。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class Post {
|
||||
@BeforeUpdate()
|
||||
updateDates() {
|
||||
this.updatedDate = new Date();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
了解有关 [listeners](listeners-and-subscribers.md)的更多信息。
|
||||
|
||||
#### `@AfterUpdate`
|
||||
|
||||
你可以在实体中定义任何名称的方法,并使用`@AfterUpdate`标记,TypeORM 将在使用存储库/管理器`save`更新现有实体之后调用它。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class Post {
|
||||
@AfterUpdate()
|
||||
updateCounters() {
|
||||
this.counter = 0;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
了解有关 [listeners](listeners-and-subscribers.md) 的更多信息
|
||||
|
||||
#### `@BeforeRemove`
|
||||
|
||||
你可以在实体中定义任何名称的方法,并使用`@BeforeRemove`标记,TypeORM 将在使用 repository/manager`remove`删除实体之前调用它。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class Post {
|
||||
@BeforeRemove()
|
||||
updateStatus() {
|
||||
this.status = "removed";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
了解有关 [listeners](listeners-and-subscribers.md)的更多信息。
|
||||
|
||||
#### `@AfterRemove`
|
||||
|
||||
你可以在实体中定义一个任何名称的方法,并使用`@AfterRemove`标记它,TypeORM 将在使用 repository/manager`remove`删除实体之后调用它。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class Post {
|
||||
@AfterRemove()
|
||||
updateStatus() {
|
||||
this.status = "removed";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
了解有关 [listeners](listeners-and-subscribers.md) 的更多信息
|
||||
|
||||
#### `@BeforeSoftRemove`
|
||||
|
||||
你可以在实体中定义任何名称的方法,并使用`@BeforeSoftRemove`标记,TypeORM 将在使用 repository/manager`softRemove`删除实体之前调用它。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class Post {
|
||||
@BeforeSoftRemove()
|
||||
updateStatus() {
|
||||
this.status = "soft-removed";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
了解有关 [listeners](listeners-and-subscribers.md)的更多信息。
|
||||
|
||||
#### `@AfterSoftRemove`
|
||||
|
||||
你可以在实体中定义一个任何名称的方法,并使用`@AfterSoftRemove`标记它,TypeORM 将在使用 repository/manager`softRemove`删除实体之后调用它。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class Post {
|
||||
@AfterSoftRemove()
|
||||
updateStatus() {
|
||||
this.status = "soft-removed";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
了解有关 [listeners](listeners-and-subscribers.md) 的更多信息
|
||||
|
||||
#### `@BeforeRecover`
|
||||
|
||||
你可以在实体中定义任何名称的方法,并使用`@BeforeRecover`标记,TypeORM 将在使用 repository/manager`recover`删除实体之前调用它。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class Post {
|
||||
@BeforeRecover()
|
||||
updateStatus() {
|
||||
this.status = "recovered";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
了解有关 [listeners](listeners-and-subscribers.md)的更多信息。
|
||||
|
||||
#### `@AfterRecover`
|
||||
|
||||
你可以在实体中定义一个任何名称的方法,并使用`@AfterRecover`标记它,TypeORM 将在使用 repository/manager`recover`删除实体之后调用它。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class Post {
|
||||
@AfterRecover()
|
||||
updateStatus() {
|
||||
this.status = "recovered";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
了解有关 [listeners](listeners-and-subscribers.md)的更多信息。
|
||||
|
||||
#### `@EventSubscriber`
|
||||
|
||||
将类标记为可以侦听特定实体事件或任何实体事件的事件订阅者。
|
||||
使用`QueryBuilder`和 repository/manager 方法触发事件。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
@EventSubscriber()
|
||||
export class PostSubscriber implements EntitySubscriberInterface<Post> {
|
||||
/**
|
||||
* 表示此订阅者仅侦听Post事件。
|
||||
*/
|
||||
listenTo() {
|
||||
return Post;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在POST INSERTED之前调用。
|
||||
*/
|
||||
beforeInsert(event: InsertEvent<Post>) {
|
||||
console.log(`BEFORE POST INSERTED: `, event.entity);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
你可以从`EntitySubscriberInterface`实现任何方法。
|
||||
要监听任何实体,只需省略`listenTo`方法并使用`any`:
|
||||
|
||||
```typescript
|
||||
@EventSubscriber()
|
||||
export class PostSubscriber implements EntitySubscriberInterface {
|
||||
/**
|
||||
* 在ENTITY INSERTED之前
|
||||
*/
|
||||
beforeInsert(event: InsertEvent<any>) {
|
||||
console.log(`BEFORE ENTITY INSERTED: `, event.entity);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
了解有关 [subscribers](listeners-and-subscribers.md)的详细信息
|
||||
|
||||
## 其他装饰器
|
||||
|
||||
#### `@Index`
|
||||
|
||||
此装饰器允许你为特定列创建数据库索引。
|
||||
它还允许你将列或列标记为唯一。
|
||||
此装饰器可以应用于列或实体本身。
|
||||
单列索引时使用或多列索引时使用。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
export class User {
|
||||
@Index()
|
||||
@Column()
|
||||
firstName: string;
|
||||
|
||||
@Index({ unique: true })
|
||||
@Column()
|
||||
lastName: string;
|
||||
}
|
||||
```
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
@Index(["firstName", "lastName"])
|
||||
@Index(["lastName", "middleName"])
|
||||
@Index(["firstName", "lastName", "middleName"], { unique: true })
|
||||
export class User {
|
||||
@Column()
|
||||
firstName: string;
|
||||
|
||||
@Column()
|
||||
lastName: string;
|
||||
|
||||
@Column()
|
||||
middleName: string;
|
||||
}
|
||||
```
|
||||
|
||||
了解有关 [indices](indices.md)的更多信息。
|
||||
|
||||
#### `@Unique`
|
||||
|
||||
此装饰器允许你为特定列创建数据库唯一约束。
|
||||
该装饰器只能应用于实体本身。
|
||||
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
@Unique(["firstName"])
|
||||
@Unique(["lastName", "middleName"])
|
||||
@Unique("UQ_NAMES", ["firstName", "lastName", "middleName"])
|
||||
export class User {
|
||||
@Column()
|
||||
firstName: string;
|
||||
|
||||
@Column()
|
||||
lastName: string;
|
||||
|
||||
@Column()
|
||||
middleName: string;
|
||||
}
|
||||
```
|
||||
|
||||
> 注意:MySQL 将唯一约束存储为唯一索引
|
||||
|
||||
#### `@Check`
|
||||
|
||||
此装饰器允许为特定列创建数据库检查约束。
|
||||
该装饰器只能应用于实体本身。
|
||||
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
@Entity()
|
||||
@Check(`"firstName" <> 'John' AND "lastName" <> 'Doe'`)
|
||||
@Check(`"age" > 18`)
|
||||
export class User {
|
||||
@Column()
|
||||
firstName: string;
|
||||
|
||||
@Column()
|
||||
lastName: string;
|
||||
|
||||
@Column()
|
||||
age: number;
|
||||
}
|
||||
```
|
||||
|
||||
> 注意:MySQL 不支持检查约束。
|
||||
|
||||
#### `@Transaction`, `@TransactionManager` 和 `@TransactionRepository`
|
||||
|
||||
`@Transaction`用于方法上,并将其所有的执行包裹到单个数据库事务中。
|
||||
必须使用`@TransactionManager`提供的管理器执行所有数据库查询
|
||||
或者使用`@TransactionRepository`注入的事务存储库。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
|
||||
@Transaction()
|
||||
save(@TransactionManager() manager: EntityManager, user: User) {
|
||||
return manager.save(user);
|
||||
}
|
||||
```
|
||||
|
||||
```typescript
|
||||
@Transaction()
|
||||
save(user: User, @TransactionRepository(User) userRepository: Repository<User>) {
|
||||
return userRepository.save(user);
|
||||
}
|
||||
```
|
||||
|
||||
```typescript
|
||||
@Transaction()
|
||||
save(@QueryParam("name") name: string, @TransactionRepository() userRepository: UserRepository) {
|
||||
return userRepository.findByName(name);
|
||||
}
|
||||
```
|
||||
|
||||
> 注意:事务中的所有操作必须且只能使用提供的`EntityManager`实例或注入的存储库。
|
||||
> 使用任何其他查询源(全局管理器,全局存储库等)将导致错误和错误。
|
||||
|
||||
了解有关 [transactions](transactions.md)的更多信息。
|
||||
|
||||
#### `@EntityRepository`
|
||||
|
||||
将自定义类标记为实体存储库。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
@EntityRepository()
|
||||
export class UserRepository {
|
||||
/// ... 定制存储库方法 ...
|
||||
}
|
||||
```
|
||||
|
||||
你可以使用`connection.getCustomRepository`或`entityManager.getCustomRepository`方法获取任何自定义创建的存储库。
|
||||
|
||||
了解有关 [custom entity repositories](custom-repository.md)的更多信息。
|
||||
|
||||
---
|
||||
|
||||
> 注意:本参考文献中没有的记录一些装饰器(如`@Tree`,`@ChildEntity`等),因为它们目前还在实验状态。期待将来看到他们的文档。
|
||||
@ -1,17 +0,0 @@
|
||||
# 使用 Query Builder 删除
|
||||
|
||||
你可以使用`QueryBuilder`创建`DELETE`查询。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
import { getConnection } from "typeorm";
|
||||
|
||||
await getConnection()
|
||||
.createQueryBuilder()
|
||||
.delete()
|
||||
.from(User)
|
||||
.where("id = :id", { id: 1 })
|
||||
.execute();
|
||||
```
|
||||
|
||||
就性能而言,这是删除数据库中的实体的最有效方法。
|
||||
@ -1,136 +0,0 @@
|
||||
# Eager 和 Lazy 关系
|
||||
|
||||
## Eager 关系
|
||||
|
||||
每次从数据库加载实体时,都会自动加载 Eager 关系。
|
||||
例如:
|
||||
|
||||
```typescript
|
||||
import { Entity, PrimaryGeneratedColumn, Column, ManyToMany } from "typeorm";
|
||||
import { Question } from "./Question";
|
||||
|
||||
@Entity()
|
||||
export class Category {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@ManyToMany(type => Question, question => question.categories)
|
||||
questions: Question[];
|
||||
}
|
||||
```
|
||||
|
||||
```typescript
|
||||
import { Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable } from "typeorm";
|
||||
import { Category } from "./Category";
|
||||
|
||||
@Entity()
|
||||
export class Question {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
title: string;
|
||||
|
||||
@Column()
|
||||
text: string;
|
||||
|
||||
@ManyToMany(type => Category, category => category.questions, {
|
||||
eager: true
|
||||
})
|
||||
@JoinTable()
|
||||
categories: Category[];
|
||||
}
|
||||
```
|
||||
|
||||
现在当你加载 questions 时,不需要加入或指定要加载的关系。它们将自动加载:
|
||||
|
||||
```typescript
|
||||
const questionRepository = connection.getRepository(Question);
|
||||
|
||||
// questions 将加载其类别 categories
|
||||
const questions = await questionRepository.find();
|
||||
```
|
||||
|
||||
Eager 关系只有在使用`find *`方法时才有效。
|
||||
如果你使用`QueryBuilder`,则禁用 eager 关系,并且必须使用`leftJoinAndSelect`来加载。
|
||||
Eager 的关系只能用于关系的一方,在关系的两边使用`eager:true`是不允许的。
|
||||
|
||||
## Lazy 关系
|
||||
|
||||
当你访问的时候会加载 Lazy 关系中的实体。
|
||||
这种关系必须有`Promise`作为类型 ,并且将值存储在一个 promise 中,
|
||||
当你加载它们时,也会返回 promise。 例如:
|
||||
|
||||
```typescript
|
||||
import { Entity, PrimaryGeneratedColumn, Column, ManyToMany } from "typeorm";
|
||||
import { Question } from "./Question";
|
||||
|
||||
@Entity()
|
||||
export class Category {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@ManyToMany(type => Question, question => question.categories)
|
||||
questions: Promise<Question[]>;
|
||||
}
|
||||
```
|
||||
|
||||
```typescript
|
||||
import { Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable } from "typeorm";
|
||||
import { Category } from "./Category";
|
||||
|
||||
@Entity()
|
||||
export class Question {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
title: string;
|
||||
|
||||
@Column()
|
||||
text: string;
|
||||
|
||||
@ManyToMany(type => Category, category => category.questions)
|
||||
@JoinTable()
|
||||
categories: Promise<Category[]>;
|
||||
}
|
||||
```
|
||||
|
||||
`categories` 是一个 Promise. 这意味着它是 lazy 的,它只能存储一个带有值的 promise。
|
||||
|
||||
例如:
|
||||
|
||||
保存这种关系:
|
||||
|
||||
```typescript
|
||||
const category1 = new Category();
|
||||
category1.name = "animals";
|
||||
await connection.manager.save(category1);
|
||||
|
||||
const category2 = new Category();
|
||||
category2.name = "zoo";
|
||||
await connection.manager.save(category2);
|
||||
|
||||
const question = new Question();
|
||||
question.categories = Promise.resolve([category1, category2]);
|
||||
await connection.manager.save(question);
|
||||
```
|
||||
|
||||
如何在 Lazy 关系中加载对象:
|
||||
|
||||
```typescript
|
||||
const question = await connection.getRepository(Question).findOne(1);
|
||||
const categories = await question.categories;
|
||||
// you'll have all question's categories inside "categories" variable now
|
||||
```
|
||||
|
||||
注意:如果你来自其他语言(Java,PHP 等)并且习惯于在任何地方使用 lazy 关系,请小心使用。
|
||||
这些语言不是异步的,延迟加载是以不同的方式实现的,这就是为什么不能使用 promises 的原因。
|
||||
在 JavaScript 和 Node.JS 中,如果你想拥有延迟加载的关系,你必须使用 promises。
|
||||
但是这是非标准技术,而且在 TypeORM 中被认为是实验性的。
|
||||