mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
refactored readme stuff and added more contributing docs
This commit is contained in:
parent
a1ff1419de
commit
86a347d1f9
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,6 +1,5 @@
|
||||
build/
|
||||
coverage/
|
||||
node_modules/
|
||||
typings/
|
||||
npm-debug.log
|
||||
config/parameters.json
|
||||
ormconfig.json
|
||||
12
CHANGELOG.md
Normal file
12
CHANGELOG.md
Normal file
@ -0,0 +1,12 @@
|
||||
# 0.0.2 (in development)
|
||||
|
||||
* lot of API refactorings
|
||||
* complete support TypeScript 2
|
||||
* optimized schema creation
|
||||
* command line tools
|
||||
* multiple drivers support
|
||||
* multiple bugfixes
|
||||
|
||||
# 0.0.1
|
||||
|
||||
* first stable version, works with TypeScript 1.x
|
||||
119
CONTRIBUTING.md
Normal file
119
CONTRIBUTING.md
Normal file
@ -0,0 +1,119 @@
|
||||
# Contributing to TypeORM
|
||||
|
||||
We would love for you to contribute to TypeORM and help make it even better than it is today!
|
||||
As a contributor, here are the guidelines we would like you to follow:
|
||||
|
||||
- [Question or Problem?](#question)
|
||||
- [Issues and Bugs](#issue)
|
||||
- [Feature Requests](#feature)
|
||||
- [Submission Guidelines](#submit)
|
||||
|
||||
## <a name="question"></a> Got a Question or Problem?
|
||||
|
||||
There are several ways how you can ask your question:
|
||||
|
||||
* You can create a question on [StackOverflow](stackoverflow.com/questions/tagged/typeorm) where the questions should be tagged with tag `typeorm`.
|
||||
* You can create issue on [github](https://github.com/typeorm/typeorm/issues)
|
||||
* You can write your questions in our [gitter channel](https://gitter.im/pleerock/typeorm)
|
||||
* If you have a Skype then try to find me there (`Umed Khudoiberdiev`)
|
||||
|
||||
Prefered way if you create your question on StackOverflow, or create a github issue.
|
||||
|
||||
## <a name="issue"></a> Found a Bug?
|
||||
|
||||
If you find a bug in the source code, you can help us by [submitting an issue](#submit-issue) to our
|
||||
[GitHub Repository](https://github.com/typeorm/typeorm).
|
||||
Even better, you can [submit a Pull Request](#submit-pr) with a fix.
|
||||
|
||||
## <a name="feature"></a> Missing a Feature?
|
||||
|
||||
You can *request* a new feature by [submitting an issue](#submit-issue) to our GitHub
|
||||
Repository. If you would like to *implement* a new feature, please submit an issue with
|
||||
a proposal for your work first, to be sure that we can use it.
|
||||
Please consider what kind of change it is:
|
||||
|
||||
* For a **Major Feature**, first open an issue and outline your proposal so that it can be
|
||||
discussed. This will also allow us to better coordinate our efforts, prevent duplication of work,
|
||||
and help you to craft the change so that it is successfully accepted into the project.
|
||||
* **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr).
|
||||
|
||||
## <a name="submit"></a> Submission Guidelines
|
||||
|
||||
### <a name="submit-issue"></a> Submitting an Issue
|
||||
|
||||
Before you submit an issue, please search the issue tracker,
|
||||
maybe an issue for your problem already exists and the discussion might inform you of workarounds readily available.
|
||||
|
||||
We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it.
|
||||
In order to reproduce bugs we ask you to provide a minimal code snippet that shows a reproduction of the problem.
|
||||
|
||||
You can file new issues by filling out our [new issue form](https://github.com/typeorm/typeorm/issues/new).
|
||||
|
||||
### <a name="submit-pr"></a> Submitting a Pull Request (PR)
|
||||
Before you submit your Pull Request (PR) consider the following guidelines:
|
||||
|
||||
* Search [GitHub](https://github.com/typeorm/typeorm/pulls) for an open or closed PR
|
||||
that relates to your submission. You don't want to duplicate effort.
|
||||
* Make your changes in a new git branch:
|
||||
|
||||
```shell
|
||||
git checkout -b my-fix-branch master
|
||||
```
|
||||
|
||||
* Create your patch, **including appropriate test cases**. Without tests your PR will not be accepted.
|
||||
* Follow our [Coding Rules](#rules).
|
||||
* Run the full TypeORM test suite, as described in the [developer documentation](DEVELOPER.md), and ensure that all tests pass.
|
||||
* Commit your changes using a descriptive commit message
|
||||
|
||||
```shell
|
||||
git commit -a
|
||||
```
|
||||
|
||||
* Push your branch to GitHub:
|
||||
|
||||
```shell
|
||||
git push origin my-fix-branch
|
||||
```
|
||||
|
||||
* In GitHub, send a pull request to `typeorm:master`.
|
||||
* If we suggest changes then:
|
||||
* Make the required updates.
|
||||
* Re-run the TypeORM test suites to ensure tests are still passing.
|
||||
* Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
|
||||
|
||||
```shell
|
||||
git rebase master -i
|
||||
git push -f
|
||||
```
|
||||
|
||||
That's it! Thank you for your contribution!
|
||||
|
||||
#### After your pull request is merged
|
||||
|
||||
After your pull request is merged, you can safely delete your branch and pull the changes
|
||||
from the main (upstream) repository:
|
||||
|
||||
* Delete the remote branch on GitHub either through the GitHub web UI or your local shell as follows:
|
||||
|
||||
```shell
|
||||
git push origin --delete my-fix-branch
|
||||
```
|
||||
|
||||
* Check out the master branch:
|
||||
|
||||
```shell
|
||||
git checkout master -f
|
||||
```
|
||||
|
||||
* Delete the local branch:
|
||||
|
||||
```shell
|
||||
git branch -D my-fix-branch
|
||||
```
|
||||
|
||||
* Update your master with the latest upstream version:
|
||||
|
||||
```shell
|
||||
git pull --ff upstream master
|
||||
```
|
||||
|
||||
95
DEVELOPER.md
Normal file
95
DEVELOPER.md
Normal file
@ -0,0 +1,95 @@
|
||||
# Building and Testing TypeORM
|
||||
|
||||
This document describes how to set up your development environment and run TypeORM test cases.
|
||||
|
||||
* [Prerequisite Software](#prerequisite-software)
|
||||
* [Getting the Sources](#getting-the-sources)
|
||||
* [Installing NPM Modules](#installing-npm-modules)
|
||||
* [Building](#building)
|
||||
* [Running Tests Locally](#running-tests-locally)
|
||||
|
||||
See the [contribution guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md)
|
||||
if you'd like to contribute to Angular.
|
||||
|
||||
## Prerequisite Software
|
||||
|
||||
Before you can build and test TypeORM, you must install and configure the
|
||||
following products on your development machine:
|
||||
|
||||
* [Git](http://git-scm.com) and/or the **GitHub app** (for [Mac](http://mac.github.com) or
|
||||
[Windows](http://windows.github.com)); [GitHub's Guide to Installing
|
||||
Git](https://help.github.com/articles/set-up-git) is a good source of information.
|
||||
|
||||
* [Node.js](http://nodejs.org), (better to install latest version) which is used to run a development web server,
|
||||
run tests, and generate distributable files.
|
||||
Depending on your system, you can install Node either from source or as a pre-packaged bundle.
|
||||
* [Mysql](https://www.mysql.com/) is required to run tests on this platform
|
||||
* [MariaDB](https://mariadb.com/) is required to run tests on this platform
|
||||
* [Postgres](https://www.postgresql.org/) is required to run tests on this platform
|
||||
* [Oracle](https://www.oracle.com/database/index.html) is required to run tests on this platform
|
||||
* [Microsoft SQL Server](https://www.microsoft.com/en-us/cloud-platform/sql-server) is required to run tests on this platform
|
||||
|
||||
## Getting the Sources
|
||||
|
||||
Fork and clone the repository:
|
||||
|
||||
1. Login to your GitHub account or create one by following the instructions given [here](https://github.com/signup/free).
|
||||
2. [Fork](http://help.github.com/forking) the [main TypeORM repository](https://github.com/typeorm/typeorm).
|
||||
3. Clone your fork of the TypeORM repository and define an `upstream` remote pointing back to
|
||||
the TypeORM repository that you forked in the first place.
|
||||
|
||||
```shell
|
||||
# Clone your GitHub repository:
|
||||
git clone git@github.com:<github username>/typeorm.git
|
||||
|
||||
# Go to the TypeORM directory:
|
||||
cd typeorm
|
||||
|
||||
# Add the main TyepORM repository as an upstream remote to your repository:
|
||||
git remote add upstream https://github.com/typeorm/typeorm.git
|
||||
```
|
||||
## Installing NPM Modules
|
||||
|
||||
Install all TypeORM dependencies by running this command:
|
||||
|
||||
```shell
|
||||
npm install
|
||||
```
|
||||
|
||||
During installation you may have some probelems with some dependencies.
|
||||
For example to proper install oracle driver you need to follow all instructions from
|
||||
[node-oracle documentation](https://github.com/oracle/node-oracledb).
|
||||
|
||||
Also install these packages globally:
|
||||
|
||||
* `npm install -g gulp` (you might need to prefix this command with `sudo`)
|
||||
* `npm install -g typescript` (you might need to prefix this command with `sudo`)
|
||||
|
||||
## Building
|
||||
|
||||
To build a distribution package of TypeORM run:
|
||||
|
||||
```shell
|
||||
gulp package
|
||||
```
|
||||
|
||||
This command will generate you a distribution package in the `build/package` directory.
|
||||
You can link (or simply copy/paste) this directory into your project and test TypeORM there
|
||||
(but make sure to keep all node_modules required by TypeORM).
|
||||
|
||||
## Running Tests Locally
|
||||
|
||||
Setup your environment configuration by copying `ormconfig.json.dist` into `ormconfig.json` and
|
||||
replacing parameters with your own.
|
||||
|
||||
Then run tests:
|
||||
|
||||
```shell
|
||||
gulp tests
|
||||
```
|
||||
|
||||
You should execute test suites before submitting a PR to github.
|
||||
All the tests are executed on our Continuous Integration infrastructure and a PR could only be merged once the tests pass.
|
||||
|
||||
|
||||
|
||||
21
LICENCE
Normal file
21
LICENCE
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2015-2016 Yakdu. http://typeorm.github.io
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@ -1,12 +0,0 @@
|
||||
## Command Line Tools
|
||||
|
||||
TODO: first need to create gulp package and tasks to perform following command line operations:
|
||||
|
||||
* create a schema
|
||||
* update a schema
|
||||
* drop a schema
|
||||
* create entity
|
||||
* create subscriber
|
||||
* create custom repository?
|
||||
* create a backup?
|
||||
* .....
|
||||
@ -1,159 +0,0 @@
|
||||
## Connection and connection options
|
||||
|
||||
You start using ORM by creating a connection with the database. In this section you will learn about:
|
||||
|
||||
* [Connection Manager that contains all connections to the databases](#connection-manager)
|
||||
* [Working with connections](#working-with-connection)
|
||||
* [Connection options](#connection-options)
|
||||
* [How to use connection manager, connections and connection options](#example)
|
||||
|
||||
### Connection Manager
|
||||
|
||||
Connection manager allows to create a new connections and retrieve previously created connections. Also it allows to import
|
||||
entities and subscribers into specific connection. These are main public methods of the `ConnectionManager`:
|
||||
|
||||
* `createConnection(options: CreateConnectionOptions): Connection`
|
||||
|
||||
Creates a new connection and registers it in the connection manager. It returns a newly created connection.
|
||||
New connection will have a given *connection name*. If connection name is not given then "default" will be used as a
|
||||
connection name. This name will be used to retrieve this connection later.
|
||||
*Driver* needs to be specified to understand what kind of database will be used for this connection.
|
||||
Right now it can be only a `mysql` driver.
|
||||
*Options* specifies connection options. More about it later.
|
||||
|
||||
* `getConnection(connectionName: string = "default"): Connection`
|
||||
|
||||
Gets a connection with a given name that was created using `createConnection` method. Connection later can be used to
|
||||
perform actions on it.
|
||||
* `importEntities(connectionName: string = "default", entities: Function[]): void`
|
||||
|
||||
Imports all given entities and registers them in the connection with a given name.
|
||||
* `importSubscribers(connectionName: string = "default", subscribers: Function[]): void`
|
||||
|
||||
Imports all given subscribers and registers them in the connection with a given name.
|
||||
* `importEntitiesFromDirectories(connectionName: string = "default", paths: string[]): void`
|
||||
|
||||
Imports all entities from the given directories and registers them in the connection with a given name.
|
||||
Paths is an array of directories from where to import entities.
|
||||
* `importSubscribersFromDirectories(connectionName: string = "default", paths: string[]): void`
|
||||
|
||||
Imports all subscribers from the given directories and registers them in the connection with a given name.
|
||||
Paths is an array of directories from where to import subscribers.
|
||||
|
||||
### Working with Connection
|
||||
|
||||
Connection is a database connection to specific database of the specific database management system.
|
||||
There are several useful methods in the Connection object:
|
||||
|
||||
* `connect()`
|
||||
Opens a new connection with the database.
|
||||
* `close()`
|
||||
Closes connection with the database.
|
||||
* `getEntityManager()`
|
||||
Gets [EntityManager](entity-manager.md) that is used to execute database operations on any entity
|
||||
that is registered in this connection.
|
||||
* `getRepository(entityClass: Function)`
|
||||
Gets a [repository](repository.md) of the specific entity that provides all functionality
|
||||
(selects/inserts/updates/deletes) with a table of the given entity class.
|
||||
|
||||
### Connection Options
|
||||
|
||||
To perform a connection you need to specify a connection options. ConnectionOptions is an interface:
|
||||
|
||||
```typescript
|
||||
export interface ConnectionOptions {
|
||||
|
||||
url?: string; // connection url
|
||||
host?: string; // database host
|
||||
port?: number; // database host port
|
||||
username?: string; // database username
|
||||
password?: string; // database password
|
||||
database?: string; // database name
|
||||
autoSchemaSync?: boolean; // set to true if you want your database schema to be auto created on each application launch
|
||||
logging?: {
|
||||
|
||||
logger?: (message: any, level: string) => void; // some specific logger to be used. By default it is a console
|
||||
logQueries?: boolean; // used if you want to log every executed query
|
||||
logOnlyFailedQueries?: boolean; // used if you want to log only failed query
|
||||
logFailedQueryError?: boolean; // used if you want to log error of the failed query
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
* To perform a connection you either must specify a connection `url`, either specify `host/port/username/password/database`.
|
||||
* `autoSchemaSync` allows you to automatically synchronize your database schema (create new tables,
|
||||
remove/rename old columns, create foreign keys, etc.) on each application run. Note that there can be errors in schema
|
||||
synchronization (mostly errors can be caused by unresolved foreign keys) and this will crash your application.
|
||||
This option should not be used in production, only during development and only if you are too lazy to use
|
||||
[command line tools](command-line-tools.md). Alternatively you can use [schema update gulp plugin](todo).
|
||||
|
||||
|
||||
### Example
|
||||
|
||||
```typescript
|
||||
// create a new connection manager
|
||||
let connectionManager = new ConnectionManager();
|
||||
|
||||
// prepare connection options
|
||||
let connectionOptions: ConnectionOptions = {
|
||||
host: "localhost",
|
||||
port: 3306,
|
||||
username: "root",
|
||||
password: "admin",
|
||||
database: "test",
|
||||
autoSchemaSync: true
|
||||
};
|
||||
|
||||
// create a new connection with mysql driver
|
||||
connectionManager.createConnection(new MysqlDriver(connectionOptions));
|
||||
|
||||
// import all entities from specific directory
|
||||
connectionManager.importEntitiesFromDirectories(__dirname + "/entities");
|
||||
|
||||
// get our connection:
|
||||
let connection = connectionManager.getConnection();
|
||||
connection.connect().then(connection => {
|
||||
|
||||
// now we are connected to the database
|
||||
// here we have a connection and we can use any of its methods
|
||||
// lets say we have a Photo entity in the /entities directory
|
||||
|
||||
// and lets create a new Photo entity instance
|
||||
|
||||
// lets try to use entity manager
|
||||
let entityManager = connection.getEntityManager();
|
||||
|
||||
// and lets create a new Photo entity instance
|
||||
let photo = new Photo();
|
||||
photo.name = "photo #1";
|
||||
|
||||
// and save it using entity manager
|
||||
entityManager
|
||||
.persist(photo)
|
||||
.then(photo => {
|
||||
console.log("Photo has been saved using entity manager");
|
||||
});
|
||||
|
||||
// lets try to use repository
|
||||
let repository = connection.getRepository(Photo);
|
||||
|
||||
// and lets create a new Photo entity instance
|
||||
let photo = new Photo();
|
||||
photo.name = "photo #2";
|
||||
|
||||
// and save it using repository
|
||||
repository
|
||||
.persist(photo)
|
||||
.then(photo => {
|
||||
console.log("Photo has been saved using repository");
|
||||
});
|
||||
|
||||
|
||||
}).catch(error => {
|
||||
// looks like some error during connection. Lets log it to find details
|
||||
console.log("error during connection to the database ", error);
|
||||
});
|
||||
```
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
## Databases and drivers
|
||||
|
||||
ORM is working with databases. To communicate with database it uses **database drivers**.
|
||||
Database Driver communicates with specific database and performs queries you need.
|
||||
|
||||
### Driver Interface
|
||||
|
||||
Right now only `mysql` database driver is supported. If you need other driver, or you simply
|
||||
want to contribute then feel free to add it - adding new drivers is not complicated.
|
||||
|
||||
Drivers are typically used within connection:
|
||||
|
||||
`let connection = connectionManager.createConnection("my-connection", new MysqlDriver());`
|
||||
|
||||
To access the driver you can do it from your connection instance:
|
||||
|
||||
`connection.driver`
|
||||
|
||||
There are several useful methods in the driver object:
|
||||
|
||||
* `driver.native`
|
||||
|
||||
Allows you to access a native layer of the driver. For example MysqlDriver is depend of npm's `mysql` package
|
||||
and `mysqlDriver.native` will give you instance to that package.
|
||||
|
||||
* `driver.nativeConnection`
|
||||
|
||||
Allows you to access to a connection instance of the native layer of the driver. For example MysqlDriver is depend of
|
||||
npm's `mysql` package and when we create a connection using that package it returns us some `connection instance` that
|
||||
we save in the driver.nativeConnection.
|
||||
|
||||
Both methods are not recommended to use, but sometimes you have no choice because of the limits of the ORM abstraction
|
||||
and you have to use them. In such situations both methods are very useful.
|
||||
|
||||
There are lot of other methods in the Driver, but you won't use them directly - they are used by other components, like
|
||||
[Entity Manager](entity-manager.md) or [Repository](repository.md). You should use those components instead.
|
||||
@ -1,196 +0,0 @@
|
||||
## Decorators Reference
|
||||
|
||||
* Table Decorators
|
||||
* [@Table](#table)
|
||||
* [@AbstractTable](#abstract-table)
|
||||
* Column Decorators
|
||||
* [@Column](#column)
|
||||
* [@PrimaryColumn](#primary-column)
|
||||
* [@CreateDateColumn](#create-date-column)
|
||||
* [@UpdateDateColumn](#update-date-column)
|
||||
* Relation Decorators
|
||||
* [@OneToOne](#one-to-one)
|
||||
* [@OneToOneInverse](#one-to-one-inverse)
|
||||
* [@ManyToOne](#many-to-one)
|
||||
* [@OneToMany](#one-to-many)
|
||||
* [@ManyToMany](#many-to-many)
|
||||
* [@ManyToManyInverse](#many-to-many-inverse)
|
||||
* Subscriber and Listener Decorators
|
||||
* [@EventSubscriber](#event-subscriber)
|
||||
* [@AfterLoad](#after-load)
|
||||
* [@BeforeInsert](#before-insert)
|
||||
* [@AfterInsert](#after-insert)
|
||||
* [@BeforeUpdate](#before-update)
|
||||
* [@AfterUpdate](#after-update)
|
||||
* [@BeforeRemove](#before-remove)
|
||||
* [@AfterRemove](#after-remove)
|
||||
* Indices
|
||||
* [@Index](#index)
|
||||
* [@CompoundIndex](#compound-index)
|
||||
|
||||
### Table Decorators
|
||||
|
||||
#### @Table
|
||||
|
||||
`@Table(name: string)`
|
||||
|
||||
This decorator is used to mark classes that will be a tables. Database schema will be created for all classes
|
||||
decorated with it, and Repository can be retrieved and used for it.
|
||||
|
||||
#### @AbstractTable
|
||||
|
||||
`@AbstractTable()`
|
||||
|
||||
Allows to use columns and relations data from the inherited metadata.
|
||||
|
||||
### Column Decorators
|
||||
|
||||
#### @Column
|
||||
|
||||
`@Column(options?: ColumnOptions)`
|
||||
`@Column(type?: ColumnType, options?: ColumnOptions)`
|
||||
|
||||
Column decorator is used to mark a specific class property as a table column. Only properties decorated with this
|
||||
decorator will be persisted to the database when entity be saved.
|
||||
|
||||
#### @PrimaryColumn
|
||||
|
||||
`@PrimaryColumn(options?: ColumnOptions)`
|
||||
`@PrimaryColumn(type?: ColumnType, options?: ColumnOptions)`
|
||||
|
||||
Column decorator is used to mark a specific class property as a table column. Only properties decorated with this
|
||||
decorator will be persisted to the database when entity be saved. Primary columns also creates a PRIMARY KEY for
|
||||
this column in a db.
|
||||
|
||||
#### @CreateDateColumn
|
||||
|
||||
`@CreateDateColumn(options?: ColumnOptions)`
|
||||
|
||||
This column will store a creation date of the inserted object. Creation date is generated and inserted only once,
|
||||
at the first time when you create an object, the value is inserted into the table, and is never touched again.
|
||||
|
||||
#### @UpdateDateColumn
|
||||
|
||||
`@UpdateDateColumn(options?: ColumnOptions)`
|
||||
|
||||
This column will store an update date of the updated object. This date is being updated each time you persist the
|
||||
object.
|
||||
|
||||
### Relation Decorators
|
||||
|
||||
#### @OneToOne
|
||||
|
||||
`@OneToOne<T>(typeFunction: (type?: any) => Function, options?: RelationOptions)`
|
||||
`@OneToOne<T>(typeFunction: (type?: any) => Function, inverseSide?: string|((object: T) => any), options?: RelationOptions)`
|
||||
|
||||
One-to-one relation allows to create direct relation between two entities. Entity1 have only one Entity2.
|
||||
Entity1 is an owner of the relationship, and storages Entity1 id on its own side.
|
||||
|
||||
#### @OneToOneInverse
|
||||
|
||||
`@OneToOneInverse<T>(typeFunction: (type?: any) => Function, options?: RelationOptions)`
|
||||
`@OneToOneInverse<T>(typeFunction: (type?: any) => Function, inverseSide?: string|((object: T) => any), options?: RelationOptions)`
|
||||
|
||||
Inverse side of the one-to-one relation. One-to-one relation allows to create direct relation between two entities.
|
||||
Entity2 have only one Entity1. Entity2 is inverse side of the relation on Entity1. Does not storage id of the
|
||||
Entity1. Entity1's id is storage on the one-to-one owner side.
|
||||
|
||||
#### @ManyToOne
|
||||
|
||||
`@ManyToOne<T>(typeFunction: (type?: any) => Function, options?: RelationOptions)`
|
||||
`@ManyToOne<T>(typeFunction: (type?: any) => Function, inverseSide?: string|((object: T) => any), options?: RelationOptions)`
|
||||
|
||||
Many-to-one relation allows to create type of relation when Entity1 can have single instance of Entity2, but
|
||||
Entity2 can have a multiple instances of Entity1. Entity1 is an owner of the relationship, and storages Entity2 id
|
||||
on its own side.
|
||||
|
||||
#### @OneToMany
|
||||
|
||||
`@OneToMany<T>(typeFunction: (type?: any) => Function, options?: RelationOptions)`
|
||||
`@OneToMany<T>(typeFunction: (type?: any) => Function, inverseSide?: string|((object: T) => any), options?: RelationOptions)`
|
||||
|
||||
One-to-many relation allows to create type of relation when Entity2 can have multiple instances of Entity1.
|
||||
Entity1 have only one Entity2. Entity1 is an owner of the relationship, and storages Entity2 id on its own side.
|
||||
|
||||
#### @ManyToMany
|
||||
|
||||
`@ManyToMany<T>(typeFunction: (type?: any) => Function, options?: RelationOptions)`
|
||||
`@ManyToMany<T>(typeFunction: (type?: any) => Function, inverseSide?: string|((object: T) => any), options?: RelationOptions)`
|
||||
|
||||
Many-to-many is a type of relationship when Entity1 can have multiple instances of Entity2, and Entity2 can have
|
||||
multiple instances of Entity1. To achieve it, this type of relation creates a junction table, where it storage
|
||||
entity1 and entity2 ids. This is owner side of the relationship.
|
||||
|
||||
#### @ManyToManyInverse
|
||||
|
||||
`@ManyToManyInverse<T>(typeFunction: (type?: any) => Function, options?: RelationOptions)`
|
||||
`@ManyToManyInverse<T>(typeFunction: (type?: any) => Function, inverseSide?: string|((object: T) => any), options?: RelationOptions)`
|
||||
|
||||
Many-to-many is a type of relationship when Entity1 can have multiple instances of Entity2, and Entity2 can have
|
||||
multiple instances of Entity1. To achieve it, this type of relation creates a junction table, where it storage
|
||||
entity1 and entity2 ids. This is inverse side of the relationship.
|
||||
|
||||
### Subscriber and Listener Decorators
|
||||
|
||||
#### @EventSubscriber
|
||||
|
||||
`@EventSubscriber()`
|
||||
|
||||
Classes decorated with this decorator will listen to ORM events and their methods will be triggered when event
|
||||
occurs. Those classes must implement EventSubscriberInterface.
|
||||
|
||||
#### @AfterLoad
|
||||
|
||||
`@AfterLoad()`
|
||||
|
||||
* Calls a method on which this decorator is applied after entity is loaded.
|
||||
|
||||
#### @BeforeInsert
|
||||
|
||||
`@BeforeInsert()`
|
||||
|
||||
Calls a method on which this decorator is applied before this entity insertion.
|
||||
|
||||
#### @AfterInsert
|
||||
|
||||
`@AfterInsert()`
|
||||
|
||||
Calls a method on which this decorator is applied after this entity insertion.
|
||||
|
||||
#### @BeforeUpdate
|
||||
|
||||
`@BeforeUpdate()`
|
||||
|
||||
Calls a method on which this decorator is applied before this entity update.
|
||||
|
||||
#### @AfterUpdate
|
||||
|
||||
`@AfterUpdate()`
|
||||
|
||||
Calls a method on which this decorator is applied after this entity update.
|
||||
|
||||
#### @BeforeRemove
|
||||
|
||||
`@BeforeRemove()`
|
||||
|
||||
Calls a method on which this decorator is applied before this entity removal.
|
||||
|
||||
#### @AfterRemove
|
||||
|
||||
`@AfterRemove()`
|
||||
|
||||
Calls a method on which this decorator is applied after this entity removal.
|
||||
|
||||
### Indices
|
||||
|
||||
#### @Index
|
||||
|
||||
`@Index(name?: string)`
|
||||
|
||||
Fields that needs to be indexed must be marked with this decorator.
|
||||
|
||||
#### @CompoundIndex
|
||||
|
||||
`@CompoundIndex(fields: string[])`
|
||||
|
||||
Compound indexes must be set on entity classes and must specify fields to be indexed.
|
||||
@ -1,70 +0,0 @@
|
||||
## Entity Manager
|
||||
|
||||
EntityManager provides functionality to work with all your entities in a single connection.
|
||||
Its like a Repository, but works with all entities.
|
||||
There are several useful methods of the EntityManager:
|
||||
|
||||
* `getRepository(entity: Entity): Repository<Entity>`
|
||||
|
||||
Gets the repository of the given entity.
|
||||
|
||||
* `hasId(entity: Entity): boolean`
|
||||
|
||||
Sometimes you want to check if your entity already has id or not. This maybe useful in situations when you want to
|
||||
check if your object is new or not.
|
||||
|
||||
* `create(entityClass: Function, plainJsObject?: Object): Entity`
|
||||
|
||||
Creates a new empty instance of entity. If `plainJsObject` is given then new entity will be created and all properties
|
||||
from the `plainJsObject` that can be mapped to this entity will be copied to the new entity.
|
||||
|
||||
* `createMany(entityClass: Function, plainJsObjects: Object[]): Entity[]`
|
||||
|
||||
Creates multiple new entities based on array of plain javascript objects. Properties for each plain javascript object
|
||||
will be copied to newly created entities if they should exist there.
|
||||
|
||||
* `initialize(entityClass: Function, object: Object): Promise<Entity>`
|
||||
|
||||
Creates a new entity from the given plan javascript object. If entity already exist 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 this new entity. This new entity is actually a loaded from the db entity with all properties
|
||||
replaced from the new object.
|
||||
|
||||
* `persist(entity: Entity): Promise<Entity>`
|
||||
|
||||
Persists (saves) a given entity in the database. If entity does not exist in the database then it inserts it,
|
||||
else if entity already exist in the database then it updates it.
|
||||
|
||||
* `remove(entity: Entity): Promise<Entity>`
|
||||
|
||||
Removes a given entity from the database.
|
||||
|
||||
* `find(entityClass: Function, conditions?: Object, options?: FindOptions): Promise<Entity[]>`
|
||||
|
||||
Finds entities that match given conditions or given find options.
|
||||
|
||||
* `findOne(entityClass: Function, conditions?: Object, options?: FindOptions): Promise<Entity>`
|
||||
|
||||
Finds the first entity that match given conditions or given find options.
|
||||
|
||||
* `findOneById(entityClass: Function, id: any, options?: FindOptions): Promise<Entity>`
|
||||
|
||||
Finds entity with a given entity id.
|
||||
|
||||
* `findAndCount(entityClass: Function, conditions?: Object, options?: FindOptions): Promise<[Entity[], number]>`
|
||||
|
||||
Finds entities that match given conditions or given find options plus gets a overall count of this items (for
|
||||
pagination purposes).
|
||||
|
||||
* `createQueryBuilder(entityClass: Function, alias: string): QueryBuilder<Entity>`
|
||||
|
||||
Creates a new query builder that can be used to build a sql query and get the results of the executed query. You can
|
||||
learn more about query builder [here](docs/query-builder.md).
|
||||
|
||||
* `query(sql: string): Promise<any>`
|
||||
|
||||
Executes raw SQL query.
|
||||
|
||||
* `transaction(runInTransaction: () => Promise<any>): Promise<any>`
|
||||
|
||||
Executes everything in the given function in a single transaction.
|
||||
@ -1,3 +0,0 @@
|
||||
## Indices and keys
|
||||
|
||||
TBD
|
||||
@ -1,54 +0,0 @@
|
||||
## Naming strategies
|
||||
|
||||
NamingStrategy is an interface that defines how auto-generated names for such things like table name, or table column
|
||||
will be named.
|
||||
|
||||
#### Interface
|
||||
|
||||
By default `DefaultNamingStrategy` is used.
|
||||
You can implement your own strategies by creating a new class and implementing `NamingStrategy` interface.
|
||||
There are three methods you need to implement:
|
||||
|
||||
* `tableName(className: string): string`
|
||||
|
||||
Gets table name from the class name. `DefaultNamingStrategy` transforms className to a sneak-case.
|
||||
|
||||
* `columnName(className: string): string`
|
||||
|
||||
Gets column name from the class property. `DefaultNamingStrategy` transforms className to a camelCase.
|
||||
|
||||
* `relationName(className: string): string`
|
||||
|
||||
Gets relation name from the class property. `DefaultNamingStrategy` transforms className to a camelCase.
|
||||
|
||||
#### Example
|
||||
|
||||
Lets create a simple naming strategy that will add a "_" before names of tables, columns and relations:
|
||||
|
||||
```typescript
|
||||
export class MyNamingStrategy implements NamingStrategy {
|
||||
|
||||
|
||||
tableName(className: string) {
|
||||
return "_" + className;
|
||||
}
|
||||
|
||||
columnName(propertyName: string) {
|
||||
return "_" + propertyName;
|
||||
}
|
||||
|
||||
relationName(propertyName: string) {
|
||||
return "_" + propertyName;
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
We also need to specify our new naming strategy on connection manager creation:
|
||||
|
||||
```typescript
|
||||
let connectionManager = new ConnectionManager();
|
||||
connectionManager.namingStrategy = new MyNamingStrategy();
|
||||
```
|
||||
|
||||
Now try to run and generate your database schema. New naming strategy should be used.
|
||||
@ -1,148 +0,0 @@
|
||||
## Query Builder
|
||||
|
||||
Query Builder allows to build a SQL queries and loads your entities from the database based on the built
|
||||
query.
|
||||
|
||||
#### create a query builder
|
||||
|
||||
To create a query builder use [EntityManager](entity-manager.md) or [Repository](repository.md):
|
||||
|
||||
```typescript
|
||||
let repository = connection.getRepository(Photo);
|
||||
let queryBuilder = repository.createQueryBuilder("photo");
|
||||
```
|
||||
|
||||
First argument of the `createQueryBuilder` is an **alias** of the object you are selecting. Basically its the same
|
||||
alias as **sql aliases**. You'll need it to make further selections.
|
||||
|
||||
#### build a query
|
||||
|
||||
There are bunch of methods to help to create a query using QueryBuilder:
|
||||
|
||||
* `queryBuilder.select(selection: string)`
|
||||
* `queryBuilder.select(selection: string[])`
|
||||
* `queryBuilder.select(...selection: string[])`
|
||||
* `queryBuilder.addSelect(selection: string)`
|
||||
* `queryBuilder.addSelect(selection: string[])`
|
||||
* `queryBuilder.addSelect(...selection: string[])`
|
||||
|
||||
Sets / adds given selections to the sql's `SELECT` group. Here you usually select aliases.
|
||||
|
||||
* `queryBuilder.where(condition: string, parameters?: { [key: string]: any })`
|
||||
* `queryBuilder.andWhere(condition: string, parameters?: { [key: string]: any })`
|
||||
* `queryBuilder.orWhere(condition: string, parameters?: { [key: string]: any })`
|
||||
|
||||
Adds sql's `WHERE` condition. For `andWhere` method it will also add "AND" before the condition and for the
|
||||
`orWhere` method it will also add "OR" before the condition. `parameters` is the array of parameters to be escaped,
|
||||
just a convenient shortcut for the `QueryBuilder#addParameters` method.
|
||||
|
||||
* `queryBuilder.having(condition: string, parameters?: { [key: string]: any })`
|
||||
* `queryBuilder.andHaving(condition: string, parameters?: { [key: string]: any })`
|
||||
* `queryBuilder.orHaving(condition: string, parameters?: { [key: string]: any })`
|
||||
|
||||
Adds sql's `HAVING` condition. For `andHaving` method it will also add "AND" before the condition and for the
|
||||
`orHaving` method it will also add "OR" before the condition. `parameters` is the array of parameters to be escaped,
|
||||
just a convenient shortcut for the `QueryBuilder#addParameters` method.
|
||||
|
||||
* `queryBuilder.orderBy(sort: string, order: "ASC"|"DESC" = "ASC")`
|
||||
* `queryBuilder.addOrderBy(sort: string, order: "ASC"|"DESC" = "ASC")`
|
||||
|
||||
Sets / adds sql's `ORDER BY` condition.
|
||||
|
||||
* `queryBuilder.groupBy(groupBy: string)`
|
||||
* `queryBuilder.addGroupBy(groupBy: string)`
|
||||
|
||||
Sets / adds sql's `GROUP BY` condition.
|
||||
|
||||
* `queryBuilder.setLimit(limit: number)`
|
||||
|
||||
Set's sql's `LIMIT`. If you are implementing pagination, LIMIT is not what you want in most of cases, because
|
||||
of how it works. It can work in some trivial queries, but in complex queries it fails. If you want to use pagination
|
||||
then use `QueryBuilder#setMaxResults` instead.
|
||||
|
||||
* `queryBuilder.setOffset(limit: number)`
|
||||
|
||||
Set's sql's `OFFSET`. If you are implementing pagination, OFFSET is not what you want in most of cases, because
|
||||
of how it works. It can work in some trivial queries, but in complex queries it fails. If you want to use pagination
|
||||
then use `QueryBuilder#setFirstResult` instead.
|
||||
|
||||
* `queryBuilder.setFirstResult(firstResult: number)`
|
||||
|
||||
Real "LIMIT" to use in queries for the pagination purposes. Use it if you want pagination.
|
||||
|
||||
* `queryBuilder.setMaxResults(maxResults: number)`
|
||||
|
||||
Real "LIMIT" to use in queries for the pagination purposes. Use it if you want pagination.
|
||||
|
||||
* `setParameter(key: string, value: any)`
|
||||
* `setParameters(parameters: Object)`
|
||||
* `addParameters(parameters: Object)`
|
||||
|
||||
Sets a single parameter value / set an object of parameters / add all parameters from the object.
|
||||
Parameters are escaped values to be used in your query, like in WHERE or HAVING expressions.
|
||||
|
||||
* `innerJoin(property: string, alias: string, conditionType?: "on"|"with", condition?: string)`
|
||||
|
||||
Adds sql's `INNER JOIN` selection on a given **property** of the object, and gives an **alias** to this selection.
|
||||
You can also specify a SQL JOIN condition type and condition.
|
||||
|
||||
* `leftJoin(property: string, alias: string, conditionType?: "on"|"with", condition?: string)`
|
||||
|
||||
Adds sql's `LEFT JOIN` selection on a given **property** of the object, and gives an **alias** to this selection.
|
||||
You can also specify a SQL JOIN condition type and condition.
|
||||
|
||||
* `innerJoinAndSelect(property: string, alias: string, conditionType?: "on"|"with", condition?: string)`
|
||||
|
||||
Adds sql's `INNER JOIN` selection on a given **property** of the object, and gives an **alias** to this selection.
|
||||
You can also specify a SQL JOIN condition type and condition. Also adds an alias into `SELECT`.
|
||||
|
||||
* `leftJoinAndSelect(property: string, alias: string, conditionType?: "on"|"with", condition?: string)`
|
||||
|
||||
Adds sql's `LEFT JOIN` selection on a given **property** of the object, and gives an **alias** to this selection.
|
||||
You can also specify a SQL JOIN condition type and condition. Also adds an alias into `SELECT`.
|
||||
|
||||
These were methods to help you to create a query. Here is example how to use some of them:
|
||||
|
||||
```typescript
|
||||
let photoRepository = connection.getRepository(Photo);
|
||||
photoRepository
|
||||
.createQueryBuilder("photo") // first argument is an alias. Alias is what you are selecting - photos. You must specify it.
|
||||
.innerJoinAndSelect("photo.metadata")
|
||||
.leftJoinAndSelect("photo.albums")
|
||||
.where("photo.isPublished=true")
|
||||
.andWhere("photo.name=:photoName OR photo.name=:bearName")
|
||||
.orderBy("photo.id", "DESC")
|
||||
.setFirstResult(5)
|
||||
.setMaxResults(10)
|
||||
.setParameters({ photoName: "My", beaName: "Mishka" });
|
||||
```
|
||||
|
||||
There is also a `getSql()` method that can be used to take a look what query QueryBuilder built for you
|
||||
and debug your queries.
|
||||
|
||||
#### get results
|
||||
|
||||
There are several methods to help you to get results:
|
||||
|
||||
* `getResults()`
|
||||
|
||||
Gets all results of the query and transforms results to the your entities.
|
||||
|
||||
* `getSingleResult()`
|
||||
|
||||
Gets the first result of the query and transforms it to the entity.
|
||||
|
||||
* `getScalarResults()`
|
||||
|
||||
Gets all results of the query in a raw - it does not transform them to entities.
|
||||
|
||||
* `getSingleScalarResult()`
|
||||
|
||||
Gets the first result of the query in a raw - it does not transform it to entity.
|
||||
|
||||
* `getCount()`
|
||||
|
||||
Gets the count - number of rows returned by this selection. Can be used for pagination.
|
||||
|
||||
There is also a `execute()` method that simply executes your query and returns you a plain result returned
|
||||
by the database driver.
|
||||
@ -1,41 +0,0 @@
|
||||
## Relations
|
||||
|
||||
One of the best sides of TypeORM is relations support. You can build relations between your tables
|
||||
easily without thinking of database schema and foreign keys. Relations are created using special decorators
|
||||
on specific fields of entity objects.
|
||||
|
||||
* [@OneToOne and @OneToOneInverse decorators](#onetoone-and-onetooneinverse-decorators)
|
||||
* [@OneToMany and @ManyToOne decorators](#onetomany-and-manytoone-decorators)
|
||||
* [@ManyToMany and @ManyToManyInverse decorators](#manytomany-and-manytomanyinverse-decorators)
|
||||
* [Self referencing](#self-referencing)
|
||||
* [Relational decorators options](#relational-decorators-options)
|
||||
|
||||
### @OneToOne and @OneToOneInverse decorators
|
||||
|
||||
TBD
|
||||
|
||||
### @OneToMany and @ManyToOne decorators
|
||||
|
||||
TBD
|
||||
|
||||
### @ManyToMany and @ManyToManyInverse decorators
|
||||
|
||||
TBD
|
||||
|
||||
### Self referencing
|
||||
|
||||
TBD
|
||||
|
||||
### Relational decorators options
|
||||
|
||||
RelationOptions is an object with additional relation options:
|
||||
|
||||
* `name?: string` - column name for the relation in the database
|
||||
* `cascadeInsert?: boolean` - allow cascade insert operations or not. If you set this to true, then any entity that
|
||||
is new (means does not exist in the database) on the relation will be persisted too.
|
||||
* `cascadeUpdate?: boolean` - allow cascade update operations or not. If you set this to true, then related entity
|
||||
will be updated in the database if it was changed.
|
||||
* `cascadeRemove?: boolean` - allow cascade remove operations or not. If you set this to true, then related entity
|
||||
will be removed from the database if it was removed from this object.
|
||||
* `onDelete?: string` - Database-level operation `ON DELETE` is an action that must be performed when related row in
|
||||
the database has been removed.
|
||||
@ -1,67 +0,0 @@
|
||||
## Repository
|
||||
|
||||
For each entity you have there is a Repository for it.
|
||||
Repository provides functionality to work with your entity.
|
||||
Repository works the same way as EntityManager, but is more specific for concrete entity class.
|
||||
There are several useful methods of the Repository:
|
||||
|
||||
* `hasId(entity: Entity): boolean`
|
||||
|
||||
Sometimes you want to check if your entity already has id or not. This maybe useful in situations when you want to
|
||||
check if your object is new or not.
|
||||
|
||||
* `create(plainJsObject?: Object): Entity`
|
||||
|
||||
Creates a new empty instance of entity. If `plainJsObject` is given then new entity will be created and all properties
|
||||
from the `plainJsObject` that can be mapped to this entity will be copied to the new entity.
|
||||
|
||||
* `createMany(plainJsObjects: Object[]): Entity[]`
|
||||
|
||||
Creates multiple new entities based on array of plain javascript objects. Properties for each plain javascript object
|
||||
will be copied to newly created entities if they should exist there.
|
||||
|
||||
* `initialize(object: Object): Promise<Entity>`
|
||||
|
||||
Creates a new entity from the given plan javascript object. If entity already exist 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 this new entity. This new entity is actually a loaded from the db entity with all properties
|
||||
replaced from the new object.
|
||||
|
||||
* `persist(entity: Entity): Promise<Entity>`
|
||||
|
||||
Persists (saves) a given entity in the database. If entity does not exist in the database then it inserts it,
|
||||
else if entity already exist in the database then it updates it.
|
||||
|
||||
* `remove(entity: Entity): Promise<Entity>`
|
||||
|
||||
Removes a given entity from the database.
|
||||
|
||||
* `find(conditions?: Object, options?: FindOptions): Promise<Entity[]>`
|
||||
|
||||
Finds entities that match given conditions or given find options.
|
||||
|
||||
* `findOne(conditions?: Object, options?: FindOptions): Promise<Entity>`
|
||||
|
||||
Finds the first entity that match given conditions or given find options.
|
||||
|
||||
* `findOneById(id: any, options?: FindOptions): Promise<Entity>`
|
||||
|
||||
Finds entity with a given entity id.
|
||||
|
||||
* `findAndCount(conditions?: Object, options?: FindOptions): Promise<[Entity[], number]>`
|
||||
|
||||
Finds entities that match given conditions or given find options plus gets a overall count of this items (for
|
||||
pagination purposes).
|
||||
|
||||
* `createQueryBuilder(alias: string): QueryBuilder<Entity>`
|
||||
|
||||
Creates a new query builder that can be used to build a sql query and get the results of the executed query. You can
|
||||
learn more about query builder [here](docs/query-builder.md).
|
||||
|
||||
* `query(sql: string): Promise<any>`
|
||||
|
||||
Executes raw SQL query.
|
||||
|
||||
* `transaction(runInTransaction: () => Promise<any>): Promise<any>`
|
||||
|
||||
Executes everything in the given function in a single transaction.
|
||||
@ -1,127 +0,0 @@
|
||||
## Subscribers and Entity Listeners
|
||||
|
||||
You can listen to events in the ORM. There two concepts you can use:
|
||||
|
||||
* [Subscribers](#subscribers)
|
||||
* [Entity Listeners](#entity-listeners)
|
||||
|
||||
### Subscribers
|
||||
|
||||
First you need to create a new subscriber class and implement `EventSubscriberInterface` interface:
|
||||
|
||||
```typescript
|
||||
import {EventSubscriber, UpdateEvent, RemoveEvent, InsertEvent} from "typeorm/listeners"
|
||||
import {EventSubscriberInterface} from "typeorm";
|
||||
|
||||
@EventSubscriber()
|
||||
export class MySubscriber implements EventSubscriberInterface<any> {
|
||||
|
||||
/**
|
||||
* Called after entity insertion.
|
||||
*/
|
||||
beforeInsert(event: InsertEvent<any>) {
|
||||
console.log(`BEFORE ENTITY INSERTED: `, event.entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after entity insertion.
|
||||
*/
|
||||
beforeUpdate(event: UpdateEvent<any>) {
|
||||
console.log(`BEFORE ENTITY UPDATED: `, event.entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after entity insertion.
|
||||
*/
|
||||
beforeRemove(event: RemoveEvent<any>) {
|
||||
console.log(`BEFORE ENTITY WITH ID ${event.entityId} REMOVED: `, event.entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after entity insertion.
|
||||
*/
|
||||
afterInsert(event: InsertEvent<any>) {
|
||||
console.log(`AFTER ENTITY INSERTED: `, event.entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after entity insertion.
|
||||
*/
|
||||
afterUpdate(event: UpdateEvent<any>) {
|
||||
console.log(`AFTER ENTITY UPDATED: `, event.entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after entity insertion.
|
||||
*/
|
||||
afterRemove(event: RemoveEvent<any>) {
|
||||
console.log(`AFTER ENTITY WITH ID ${event.entityId} REMOVED: `, event.entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after entity is loaded.
|
||||
*/
|
||||
afterLoad(entity: any) {
|
||||
console.log(`AFTER ENTITY LOADED: `, entity);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
To register a subscriber you need to register it:
|
||||
|
||||
```typescript
|
||||
connectionManager.importSubscribers([MySubscriber]);
|
||||
```
|
||||
|
||||
### Entity Listeners
|
||||
|
||||
You can also use listeners in your entities. Such listeners can be convenient for a trivial operations.
|
||||
|
||||
```typescript
|
||||
import {Table} from "typeorm/tables";
|
||||
import {AfterLoad, AfterInsert, BeforeInsert, BeforeUpdate, AfterUpdate, BeforeRemove, AfterRemove} from "typeorm/listeners";
|
||||
|
||||
@Table("posts")
|
||||
export class Post {
|
||||
|
||||
// ... columns ...
|
||||
|
||||
@AfterLoad()
|
||||
generateRandomNumbers() {
|
||||
console.log(`event: Post entity has been loaded and callback executed`);
|
||||
}
|
||||
|
||||
@BeforeInsert()
|
||||
doSomethingBeforeInsertion() {
|
||||
console.log("event: Post entity will be inserted so soon...");
|
||||
}
|
||||
|
||||
@AfterInsert()
|
||||
doSomethingAfterInsertion() {
|
||||
console.log("event: Post entity has been inserted and callback executed");
|
||||
}
|
||||
|
||||
@BeforeUpdate()
|
||||
doSomethingBeforeUpdate() {
|
||||
console.log("event: Post entity will be updated so soon...");
|
||||
}
|
||||
|
||||
@AfterUpdate()
|
||||
doSomethingAfterUpdate() {
|
||||
console.log("event: Post entity has been updated and callback executed");
|
||||
}
|
||||
|
||||
@BeforeRemove()
|
||||
doSomethingBeforeRemove() {
|
||||
console.log("event: Post entity will be removed so soon...");
|
||||
}
|
||||
|
||||
@AfterRemove()
|
||||
doSomethingAfterRemove() {
|
||||
console.log("event: Post entity has been removed and callback executed");
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
@ -1,173 +0,0 @@
|
||||
## Table columns
|
||||
|
||||
Entity consist of columns. For each entity column, column in the database will be created.
|
||||
|
||||
* [@Column decorator](#@column)
|
||||
* [@PrimaryColumn decorator](#@primary-column)
|
||||
* [@CreateDateColumn decorator](#@create-date-column)
|
||||
* [@UpdateDateColumn decorator](#@update-date-column)
|
||||
* [Column types](#column-type)
|
||||
* [Column options](#column-options)
|
||||
* [Columns usage example](#example)
|
||||
|
||||
#### @Column
|
||||
|
||||
Column decorator simply marks an entity property to be a table column.
|
||||
There are several column decorator signatures:
|
||||
|
||||
```typescript
|
||||
@Column(options?: ColumnOptions)
|
||||
@Column(type?: ColumnType, options?: ColumnOptions)
|
||||
```
|
||||
|
||||
#### @PrimaryColumn
|
||||
|
||||
PrimaryColumn marks an entity property as a column and creates a primary key for it.
|
||||
There are several column decorator signatures:
|
||||
|
||||
```typescript
|
||||
@PrimaryColumn(options?: ColumnOptions)
|
||||
@PrimaryColumn(type?: ColumnType, options?: ColumnOptions)
|
||||
```
|
||||
|
||||
#### @CreateDateColumn
|
||||
|
||||
CreateDateColumn adds a simple datetime column to the table. During its first persistence (e.g. insertion) it
|
||||
sets current date as a value of the property object.
|
||||
|
||||
```typescript
|
||||
@CreateDateColumn(options?: ColumnOptions)
|
||||
```
|
||||
|
||||
#### @UpdateDateColumn
|
||||
|
||||
UpdateDateColumn adds a simple datetime column to the table. Each time object is persisted, this column value is updated
|
||||
to the current date.
|
||||
|
||||
```typescript
|
||||
@CreateDateColumn(options?: ColumnOptions)
|
||||
```
|
||||
|
||||
#### ColumnType
|
||||
|
||||
ColumnType can be one of:
|
||||
|
||||
* `string` will be mapped to db's `varchar`
|
||||
* `text` will be mapped to db's `text`
|
||||
* `number` will be mapped to db's `double`
|
||||
* `integer` will be mapped to db's `int`
|
||||
* `int` will be mapped to db's `int`
|
||||
* `smallint` will be mapped to db's `int`
|
||||
* `bigint` will be mapped to db's `int`
|
||||
* `float` will be mapped to db's `float`
|
||||
* `double` will be mapped to db's `double`
|
||||
* `decimal` will be mapped to db's `decimal`
|
||||
* `date` will be mapped to db's `datetime`
|
||||
* `time` will be mapped to db's `time`
|
||||
* `datetime` will be mapped to db's `datetime`
|
||||
* `timestamp` will be mapped to db's `timestamp`
|
||||
* `boolean` will be mapped to db's `boolean`
|
||||
* `json` will be mapped to db's `text`
|
||||
* `simple_array` will be mapped to db's `text`
|
||||
|
||||
If you omit a column type, type will be guessed automatically based on variable type:
|
||||
|
||||
* `number` will be mapped to `float`
|
||||
* `boolean` will be mapped to `boolean`
|
||||
* `string` will be mapped to `varchar`
|
||||
* `Date` will be mapped to `datetime`
|
||||
|
||||
#### ColumnOptions
|
||||
|
||||
ColumnOptions is an object with additional column options:
|
||||
|
||||
* `name?: string` - column name in the database
|
||||
* `type?: ColumnType` - column type also can be specified via column options
|
||||
* `length?: string` - column type's length. For example type = "string" and length = 100 means that ORM will create a
|
||||
column with type varchar(100).
|
||||
* `generated?: boolean` - specifies if this column will use AUTO_INCREMENT or not (e.g. generated number)
|
||||
* `unique?: boolean` - specifies if column's value must be unique or not.
|
||||
* `nullable?: boolean` - indicates if column's value can be set to NULL.
|
||||
* `columnDefinition?: string` - Extra column definition. Should be used only in emergency situations.
|
||||
Note that if you'll use this property auto schema generation will not work properly anymore.
|
||||
* `comment?: string` - column comment
|
||||
* `precision?: number` - The precision for a decimal (exact numeric) column (applies only for decimal column), which is the maximum
|
||||
number of digits that are stored for the values.
|
||||
* `scale?: number` - The scale for a decimal (exact numeric) column (applies only for decimal column), which represents the number
|
||||
of digits to the right of the decimal point and must not be greater than precision.
|
||||
* `collation?: string` - Column collation. Note that not all databases support it.
|
||||
|
||||
#### Example
|
||||
|
||||
```typescript
|
||||
@Table("photo")
|
||||
class Photo {
|
||||
|
||||
/**
|
||||
* Primary column with auto increment key.
|
||||
*/
|
||||
@PrimaryColumn("int", { generated: true })
|
||||
id: number;
|
||||
|
||||
/**
|
||||
* Simple string column.
|
||||
*/
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* Simple boolean column.
|
||||
*/
|
||||
@Column()
|
||||
isPublished: boolean;
|
||||
|
||||
/**
|
||||
* Simple numeric (float) column.
|
||||
*/
|
||||
@Column()
|
||||
scale: number;
|
||||
|
||||
/**
|
||||
* Simple numeric (integer) column.
|
||||
*/
|
||||
@Column("integer")
|
||||
size: number;
|
||||
|
||||
/**
|
||||
* Simple column that contains a date.
|
||||
*/
|
||||
@Column()
|
||||
publishedDate: Date;
|
||||
|
||||
/**
|
||||
* Simple column that contains a big text.
|
||||
*/
|
||||
@Column("text")
|
||||
description: string;
|
||||
|
||||
/**
|
||||
* Simple column that contains a short text.
|
||||
*/
|
||||
@Column({
|
||||
length: 3
|
||||
})
|
||||
locale: string;
|
||||
|
||||
/**
|
||||
* This column's value must be unique.
|
||||
*/
|
||||
@Column({
|
||||
unique: true
|
||||
})
|
||||
slug: string;
|
||||
|
||||
/**
|
||||
* This column's value can be nullable.
|
||||
*/
|
||||
@Column({
|
||||
nullable: true
|
||||
})
|
||||
metadata: string;
|
||||
|
||||
}
|
||||
```
|
||||
@ -1,57 +0,0 @@
|
||||
## Tables and table inheritance
|
||||
|
||||
### Tables
|
||||
|
||||
ORM creates tables for each class that you decorated with `@Table` decorator and which you loaded into your
|
||||
connection.
|
||||
|
||||
```typescript
|
||||
@Table("photos")
|
||||
export class Photo {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Each table must have a primary column (using `@PrimaryColumn` decotator) [*todo: really?*] and can contain
|
||||
other [columns](table-columns.md).
|
||||
|
||||
### Table inheritance
|
||||
|
||||
If multiple tables has same properties you may want to find them a common abstraction and create a base
|
||||
class for them. In this base class you'll have a common for all inherited classes columns. To ahieve this you
|
||||
must mark your table with `@AbstractTable()` decorator:
|
||||
|
||||
```typescript
|
||||
@AbstractTable()
|
||||
export class BasePhoto {
|
||||
|
||||
@PrimaryColumn("int", { generated: true })
|
||||
id: string;
|
||||
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@Column()
|
||||
url: string;
|
||||
|
||||
}
|
||||
|
||||
@Table("public_photos")
|
||||
export class Photo extends BasePhoto {
|
||||
|
||||
@Column()
|
||||
authorName: string;
|
||||
|
||||
}
|
||||
|
||||
@Table("private_photos")
|
||||
export class Photo extends BasePhoto {
|
||||
|
||||
@Column()
|
||||
isPublished: boolean;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
This will create you two tables `public_photos` and `private_photos` with 5 columns each.
|
||||
Right now only columns are inherited. Relations are ignored.
|
||||
@ -1,17 +0,0 @@
|
||||
## Updating database schema
|
||||
|
||||
Your database schema is managed automatically by ORM:
|
||||
|
||||
* tables are created for all entities
|
||||
* columns are created for all entity columns
|
||||
* foreign keys are set for all relations
|
||||
* junction tables are created for all many-to-many relations
|
||||
|
||||
All this must be in sync to make ORM to work correctly. To make a synchronization there are two ways:
|
||||
|
||||
* set in [connection options](connection-and-connection-options.md#connection-options) `autoSchemaSync: true`.
|
||||
In this case database schema will be automatically synchronized each time you run the application.
|
||||
|
||||
* use [schema update gulp plugin](todo) and run schema synchronization process each time you need it.
|
||||
|
||||
First approach is not recommended to use in production, however it can be handy during development.
|
||||
@ -164,7 +164,7 @@ export class Gulpfile {
|
||||
*/
|
||||
@Task()
|
||||
coveragePre() {
|
||||
return gulp.src(["./build/es5/src/**/*.js"])
|
||||
return gulp.src(["./build/compiled/src/**/*.js"])
|
||||
.pipe(istanbul())
|
||||
.pipe(istanbul.hookRequire());
|
||||
}
|
||||
@ -178,7 +178,7 @@ export class Gulpfile {
|
||||
chai.use(require("sinon-chai"));
|
||||
chai.use(require("chai-as-promised"));
|
||||
|
||||
return gulp.src(["./build/es5/test/**/*.js"])
|
||||
return gulp.src(["./build/compiled/test/**/*.js"])
|
||||
.pipe(mocha())
|
||||
.pipe(istanbul.writeReports());
|
||||
}
|
||||
|
||||
14
ormconfig.json.dist
Normal file
14
ormconfig.json.dist
Normal file
@ -0,0 +1,14 @@
|
||||
[
|
||||
{
|
||||
"name": "default",
|
||||
"driver": {
|
||||
"type": "mysql",
|
||||
"host": "localhost",
|
||||
"port": 3306,
|
||||
"username": "root",
|
||||
"password": "admin",
|
||||
"database": "test"
|
||||
},
|
||||
"autoSchemaSync": true
|
||||
}
|
||||
]
|
||||
@ -3,7 +3,7 @@
|
||||
"private": true,
|
||||
"version": "0.0.2-alpha.67",
|
||||
"description": "Data-mapper ORM for Typescript",
|
||||
"license": "Apache-2.0",
|
||||
"license": "MIT",
|
||||
"readmeFilename": "README.md",
|
||||
"author": {
|
||||
"name": "Umed Khudoiberdiev",
|
||||
|
||||
@ -10,9 +10,9 @@ import {PostAuthor} from "./entity/PostAuthor";
|
||||
|
||||
const options: ConnectionOptions = {
|
||||
driver: {
|
||||
type: "postgres",
|
||||
type: "mysql",
|
||||
host: "localhost",
|
||||
port: 5432,
|
||||
port: 3306,
|
||||
username: "root",
|
||||
password: "admin",
|
||||
database: "test"
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
{
|
||||
"version": "2.0.2",
|
||||
"version": "2.0.3",
|
||||
"compilerOptions": {
|
||||
"lib": ["es5", "es6", "dom"],
|
||||
"outDir": "build/es5",
|
||||
"outDir": "build/compiled",
|
||||
"target": "es6",
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
@ -18,6 +18,8 @@
|
||||
"strictNullChecks": true
|
||||
},
|
||||
"exclude": [
|
||||
"tmp",
|
||||
"temp",
|
||||
"build",
|
||||
"node_modules"
|
||||
]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user