TypeORM
ORM for TypeScript and JavaScript (ES7, ES6, ES5). Supports MySQL, PostgreS...
README
Features
- ```typescript
- import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"
- @Entity()
- export class User {
- @PrimaryGeneratedColumn()
- id: number
- @Column()
- firstName: string
- @Column()
- lastName: string
- @Column()
- age: number
- }
- ```
- ```typescript
- const userRepository = MyDataSource.getRepository(User)
- const user = new User()
- user.firstName = "Timber"
- user.lastName = "Saw"
- user.age = 25
- await userRepository.save(user)
- const allUsers = await userRepository.find()
- const firstUser = await userRepository.findOneBy({
- id: 1,
- }) // find by id
- const timber = await userRepository.findOneBy({
- firstName: "Timber",
- lastName: "Saw",
- }) // find by firstName and lastName
- await userRepository.remove(timber)
- ```
- ```typescript
- import { Entity, PrimaryGeneratedColumn, Column, BaseEntity } from "typeorm"
- @Entity()
- export class User extends BaseEntity {
- @PrimaryGeneratedColumn()
- id: number
- @Column()
- firstName: string
- @Column()
- lastName: string
- @Column()
- age: number
- }
- ```
- ```typescript
- const user = new User()
- user.firstName = "Timber"
- user.lastName = "Saw"
- user.age = 25
- await user.save()
- const allUsers = await User.find()
- const firstUser = await User.findOneBy({
- id: 1,
- })
- const timber = await User.findOneBy({
- firstName: "Timber",
- lastName: "Saw"
- })
- await timber.remove()
- ```
Installation
- ```
- npm install @sap/hana-client
- npm install hdb-pool
- ```
- ```
- npm install @google-cloud/spanner --save
- ```
- ``` sh
- # Linux/macOS
- export GOOGLE_APPLICATION_CREDENTIALS="KEY_PATH"
- # Windows
- set GOOGLE_APPLICATION_CREDENTIALS=KEY_PATH
- # Replace KEY_PATH with the path of the JSON file that contains your service account key.
- ```
- ``` sh
- # Linux/macOS
- export SPANNER_EMULATOR_HOST=localhost:9010
- # Windows
- set SPANNER_EMULATOR_HOST=localhost:9010
- ```
TypeScript configuration
- ``` json
- "emitDecoratorMetadata": true,
- "experimentalDecorators": true,
- ```
Quick Start
- ``` sh
- npx typeorm init --name MyProject --database postgres
- ```
- ```
- MyProject
- ├── src // place of your TypeScript code
- │ ├── entity // place where your entities (database models) are stored
- │ │ └── User.ts // sample entity
- │ ├── migration // place where your migrations are stored
- │ ├── data-source.ts // data source and all connection configuration
- │ └── index.ts // start point of your application
- ├── .gitignore // standard gitignore file
- ├── package.json // node module dependencies
- ├── README.md // simple readme file
- └── tsconfig.json // TypeScript compiler options
- ```
You can also run typeorm init on an existing node project, but be careful - it may override some files you already have.
- ``` sh
- cd MyProject
- npm install
- ```
- ```ts
- export const AppDataSource = new DataSource({
- type: "postgres",
- host: "localhost",
- port: 5432,
- username: "test",
- password: "test",
- database: "test",
- synchronize: true,
- logging: true,
- entities: [Post, Category],
- subscribers: [],
- migrations: [],
- })
- ```
- ``` sh
- npm start
- ```
You can generate an ESM project by running
npx typeorm init --name MyProject --database postgres --module esm command.
You can generate an even more advanced project with express installed by running
npx typeorm init --name MyProject --database mysql --express command.
You can generate a docker-compose file by running
npx typeorm init --name MyProject --database postgres --docker command.
Step-by-Step Guide
Create a model
- ```typescript
- export class Photo {
- id: number
- name: string
- description: string
- filename: string
- views: number
- isPublished: boolean
- }
- ```
Create an entity
- ```typescript
- import { Entity } from "typeorm"
- @Entity()
- export class Photo {
- id: number
- name: string
- description: string
- filename: string
- views: number
- isPublished: boolean
- }
- ```
Adding table columns
- ```typescript
- import { Entity, Column } from "typeorm"
- @Entity()
- export class Photo {
- @Column()
- id: number
- @Column()
- name: string
- @Column()
- description: string
- @Column()
- filename: string
- @Column()
- views: number
- @Column()
- isPublished: boolean
- }
- ```
Creating a primary column
- ```typescript
- import { Entity, Column, PrimaryColumn } from "typeorm"
- @Entity()
- export class Photo {
- @PrimaryColumn()
- id: number
- @Column()
- name: string
- @Column()
- description: string
- @Column()
- filename: string
- @Column()
- views: number
- @Column()
- isPublished: boolean
- }
- ```
Creating an auto-generated column
- ```typescript
- import { Entity, Column, PrimaryGeneratedColumn } from "typeorm"
- @Entity()
- export class Photo {
- @PrimaryGeneratedColumn()
- id: number
- @Column()
- name: string
- @Column()
- description: string
- @Column()
- filename: string
- @Column()
- views: number
- @Column()
- isPublished: boolean
- }
- ```
Column data types
- ```typescript
- import { Entity, Column, PrimaryGeneratedColumn } from "typeorm"
- @Entity()
- export class Photo {
- @PrimaryGeneratedColumn()
- id: number
- @Column({
- length: 100,
- })
- name: string
- @Column("text")
- description: string
- @Column()
- filename: string
- @Column("double")
- views: number
- @Column()
- isPublished: boolean
- }
- ```
Creating a new DataSource
- ```typescript
- import "reflect-metadata"
- import { DataSource } from "typeorm"
- import { Photo } from "./entity/Photo"
- const AppDataSource = new DataSource({
- type: "postgres",
- host: "localhost",
- port: 5432,
- username: "root",
- password: "admin",
- database: "test",
- entities: [Photo],
- synchronize: true,
- logging: false,
- })
- // to initialize initial connection with the database, register all entities
- // and "synchronize" database schema, call "initialize()" method of a newly created database
- // once in your application bootstrap
- AppDataSource.initialize()
- .then(() => {
- // here you can start to work with your database
- })
- .catch((error) => console.log(error))
- ```
Running the application
- ``` sh
- +-------------+--------------+----------------------------+
- | photo |
- +-------------+--------------+----------------------------+
- | id | int(11) | PRIMARY KEY AUTO_INCREMENT |
- | name | varchar(100) | |
- | description | text | |
- | filename | varchar(255) | |
- | views | int(11) | |
- | isPublished | boolean | |
- +-------------+--------------+----------------------------+
- ```
Creating and inserting a photo into the database
- ```typescript
- import { Photo } from "./entity/Photo"
- import { AppDataSource } from "./index"
- const photo = new Photo()
- photo.name = "Me and Bears"
- photo.description = "I am near polar bears"
- photo.filename = "photo-with-bears.jpg"
- photo.views = 1
- photo.isPublished = true
- await AppDataSource.manager.save(photo)
- console.log("Photo has been saved. Photo id is", photo.id)
- ```
Using Entity Manager
- ```typescript
- import { Photo } from "./entity/Photo"
- import { AppDataSource } from "./index"
- const savedPhotos = await AppDataSource.manager.find(Photo)
- console.log("All photos from the db: ", savedPhotos)
- ```
Using Repositories
- ```typescript
- import { Photo } from "./entity/Photo"
- import { AppDataSource } from "./index"
- const photo = new Photo()
- photo.name = "Me and Bears"
- photo.description = "I am near polar bears"
- photo.filename = "photo-with-bears.jpg"
- photo.views = 1
- photo.isPublished = true
- const photoRepository = AppDataSource.getRepository(Photo)
- await photoRepository.save(photo)
- console.log("Photo has been saved")
- const savedPhotos = await photoRepository.find()
- console.log("All photos from the db: ", savedPhotos)
- ```
Loading from the database
- ```typescript
- import { Photo } from "./entity/Photo"
- import { AppDataSource } from "./index"
- const photoRepository = AppDataSource.getRepository(Photo)
- const allPhotos = await photoRepository.find()
- console.log("All photos from the db: ", allPhotos)
- const firstPhoto = await photoRepository.findOneBy({
- id: 1,
- })
- console.log("First photo from the db: ", firstPhoto)
- const meAndBearsPhoto = await photoRepository.findOneBy({
- name: "Me and Bears",
- })
- console.log("Me and Bears photo from the db: ", meAndBearsPhoto)
- const allViewedPhotos = await photoRepository.findBy({ views: 1 })
- console.log("All viewed photos: ", allViewedPhotos)
- const allPublishedPhotos = await photoRepository.findBy({ isPublished: true })
- console.log("All published photos: ", allPublishedPhotos)
- const [photos, photosCount] = await photoRepository.findAndCount()
- console.log("All photos: ", photos)
- console.log("Photos count: ", photosCount)
- ```
Updating in the database
- ```typescript
- import { Photo } from "./entity/Photo"
- import { AppDataSource } from "./index"
- const photoRepository = AppDataSource.getRepository(Photo)
- const photoToUpdate = await photoRepository.findOneBy({
- id: 1,
- })
- photoToUpdate.name = "Me, my friends and polar bears"
- await photoRepository.save(photoToUpdate)
- ```
Removing from the database
- ```typescript
- import { Photo } from "./entity/Photo"
- import { AppDataSource } from "./index"
- const photoRepository = AppDataSource.getRepository(Photo)
- const photoToRemove = await photoRepository.findOneBy({
- id: 1,
- })
- await photoRepository.remove(photoToRemove)
- ```
Creating a one-to-one relation
- ```typescript
- import {
- Entity,
- Column,
- PrimaryGeneratedColumn,
- OneToOne,
- JoinColumn,
- } from "typeorm"
- import { Photo } from "./Photo"
- @Entity()
- export class PhotoMetadata {
- @PrimaryGeneratedColumn()
- id: number
- @Column("int")
- height: number
- @Column("int")
- width: number
- @Column()
- orientation: string
- @Column()
- compressed: boolean
- @Column()
- comment: string
- @OneToOne(() => Photo)
- @JoinColumn()
- photo: Photo
- }
- ```
- ``` sh
- +-------------+--------------+----------------------------+
- | photo_metadata |
- +-------------+--------------+----------------------------+
- | id | int(11) | PRIMARY KEY AUTO_INCREMENT |
- | height | int(11) | |
- | width | int(11) | |
- | comment | varchar(255) | |
- | compressed | boolean | |
- | orientation | varchar(255) | |
- | photoId | int(11) | FOREIGN KEY |
- +-------------+--------------+----------------------------+
- ```
Save a one-to-one relation
- ```typescript
- import { Photo } from "./entity/Photo"
- import { PhotoMetadata } from "./entity/PhotoMetadata"
- // create a photo
- const photo = new Photo()
- photo.name = "Me and Bears"
- photo.description = "I am near polar bears"
- photo.filename = "photo-with-bears.jpg"
- photo.views = 1
- photo.isPublished = true
- // create a photo metadata
- const metadata = new PhotoMetadata()
- metadata.height = 640
- metadata.width = 480
- metadata.compressed = true
- metadata.comment = "cybershoot"
- metadata.orientation = "portrait"
- metadata.photo = photo // this way we connect them
- // get entity repositories
- const photoRepository = AppDataSource.getRepository(Photo)
- const metadataRepository = AppDataSource.getRepository(PhotoMetadata)
- // first we should save a photo
- await photoRepository.save(photo)
- // photo is saved. Now we need to save a photo metadata
- await metadataRepository.save(metadata)
- // done
- console.log(
- "Metadata is saved, and the relation between metadata and photo is created in the database too",
- )
- ```
Inverse side of the relationship
- ```typescript
- import {
- Entity,
- Column,
- PrimaryGeneratedColumn,
- OneToOne,
- JoinColumn,
- } from "typeorm"
- import { Photo } from "./Photo"
- @Entity()
- export class PhotoMetadata {
- /* ... other columns */
- @OneToOne(() => Photo, (photo) => photo.metadata)
- @JoinColumn()
- photo: Photo
- }
- ```
- ```typescript
- import { Entity, Column, PrimaryGeneratedColumn, OneToOne } from "typeorm"
- import { PhotoMetadata } from "./PhotoMetadata"
- @Entity()
- export class Photo {
- /* ... other columns */
- @OneToOne(() => PhotoMetadata, (photoMetadata) => photoMetadata.photo)
- metadata: PhotoMetadata
- }
- ```
Relations in ESM projects
- ```typescript
- import {
- Entity,
- Column,
- PrimaryGeneratedColumn,
- OneToOne,
- JoinColumn,
- Relation,
- } from "typeorm"
- import { Photo } from "./Photo"
- @Entity()
- export class PhotoMetadata {
- /* ... other columns */
- @OneToOne(() => Photo, (photo) => photo.metadata)
- @JoinColumn()
- photo: Relation<Photo>
- }
- ```
- ```typescript
- import {
- Entity,
- Column,
- PrimaryGeneratedColumn,
- OneToOne,
- Relation,
- } from "typeorm"
- import { PhotoMetadata } from "./PhotoMetadata"
- @Entity()
- export class Photo {
- /* ... other columns */
- @OneToOne(() => PhotoMetadata, (photoMetadata) => photoMetadata.photo)
- metadata: Relation<PhotoMetadata>
- }
- ```
Loading objects with their relations
- ```typescript
- import { Photo } from "./entity/Photo"
- import { PhotoMetadata } from "./entity/PhotoMetadata"
- import { AppDataSource } from "./index"
- const photoRepository = AppDataSource.getRepository(Photo)
- const photos = await photoRepository.find({
- relations: {
- metadata: true,
- },
- })
- ```
- ```typescript
- import { Photo } from "./entity/Photo"
- import { PhotoMetadata } from "./entity/PhotoMetadata"
- import { AppDataSource } from "./index"
- const photos = await AppDataSource.getRepository(Photo)
- .createQueryBuilder("photo")
- .innerJoinAndSelect("photo.metadata", "metadata")
- .getMany()
- ```
Using cascades to automatically save related objects
- ```typescript
- export class Photo {
- /// ... other columns
- @OneToOne(() => PhotoMetadata, (metadata) => metadata.photo, {
- cascade: true,
- })
- metadata: PhotoMetadata
- }
- ```
- ```typescript
- import { AppDataSource } from "./index"
- // create photo object
- const photo = new Photo()
- photo.name = "Me and Bears"
- photo.description = "I am near polar bears"
- photo.filename = "photo-with-bears.jpg"
- photo.isPublished = true
- // create photo metadata object
- const metadata = new PhotoMetadata()
- metadata.height = 640
- metadata.width = 480
- metadata.compressed = true
- metadata.comment = "cybershoot"
- metadata.orientation = "portrait"
- photo.metadata = metadata // this way we connect them
- // get repository
- const photoRepository = AppDataSource.getRepository(Photo)
- // saving a photo also save the metadata
- await photoRepository.save(photo)
- console.log("Photo is saved, photo metadata is saved too.")
- ```
Creating a many-to-one / one-to-many relation
- ```typescript
- import {
- Entity,
- Column,
- PrimaryGeneratedColumn,
- OneToMany,
- JoinColumn,
- } from "typeorm"
- import { Photo } from "./Photo"
- @Entity()
- export class Author {
- @PrimaryGeneratedColumn()
- id: number
- @Column()
- name: string
- @OneToMany(() => Photo, (photo) => photo.author) // note: we will create author property in the Photo class below
- photos: Photo[]
- }
- ```
- ```typescript
- import { Entity, Column, PrimaryGeneratedColumn, ManyToOne } from "typeorm"
- import { PhotoMetadata } from "./PhotoMetadata"
- import { Author } from "./Author"
- @Entity()
- export class Photo {
- /* ... other columns */
- @ManyToOne(() => Author, (author) => author.photos)
- author: Author
- }
- ```
- ``` sh
- +-------------+--------------+----------------------------+
- | author |
- +-------------+--------------+----------------------------+
- | id | int(11) | PRIMARY KEY AUTO_INCREMENT |
- | name | varchar(255) | |
- +-------------+--------------+----------------------------+
- ```
- ``` sh
- +-------------+--------------+----------------------------+
- | photo |
- +-------------+--------------+----------------------------+
- | id | int(11) | PRIMARY KEY AUTO_INCREMENT |
- | name | varchar(255) | |
- | description | varchar(255) | |
- | filename | varchar(255) | |
- | isPublished | boolean | |
- | authorId | int(11) | FOREIGN KEY |
- +-------------+--------------+----------------------------+
- ```
Creating a many-to-many relation
- ```typescript
- import {
- Entity,
- PrimaryGeneratedColumn,
- Column,
- ManyToMany,
- JoinTable,
- } from "typeorm"
- @Entity()
- export class Album {
- @PrimaryGeneratedColumn()
- id: number
- @Column()
- name: string
- @ManyToMany(() => Photo, (photo) => photo.albums)
- @JoinTable()
- photos: Photo[]
- }
- ```
- ```typescript
- export class Photo {
- /// ... other columns
- @ManyToMany(() => Album, (album) => album.photos)
- albums: Album[]
- }
- ```
- ``` sh
- +-------------+--------------+----------------------------+
- | album_photos_photo_albums |
- +-------------+--------------+----------------------------+
- | album_id | int(11) | PRIMARY KEY FOREIGN KEY |
- | photo_id | int(11) | PRIMARY KEY FOREIGN KEY |
- +-------------+--------------+----------------------------+
- ```
- ```typescript
- const options: DataSourceOptions = {
- // ... other options
- entities: [Photo, PhotoMetadata, Author, Album],
- }
- ```
- ```typescript
- import { AppDataSource } from "./index"
- // create a few albums
- const album1 = new Album()
- album1.name = "Bears"
- await AppDataSource.manager.save(album1)
- const album2 = new Album()
- album2.name = "Me"
- await AppDataSource.manager.save(album2)
- // create a few photos
- const photo = new Photo()
- photo.name = "Me and Bears"
- photo.description = "I am near polar bears"
- photo.filename = "photo-with-bears.jpg"
- photo.views = 1
- photo.isPublished = true
- photo.albums = [album1, album2]
- await AppDataSource.manager.save(photo)
- // now our photo is saved and albums are attached to it
- // now lets load them:
- const loadedPhoto = await AppDataSource.getRepository(Photo).findOne({
- where: {
- id: 1,
- },
- relations: {
- albums: true,
- },
- })
- ```
- ```typescript
- {
- id: 1,
- name: "Me and Bears",
- description: "I am near polar bears",
- filename: "photo-with-bears.jpg",
- albums: [{
- id: 1,
- name: "Bears"
- }, {
- id: 2,
- name: "Me"
- }]
- }
- ```
Using QueryBuilder
- ```typescript
- const photos = await AppDataSource.getRepository(Photo)
- .createQueryBuilder("photo") // first argument is an alias. Alias is what you are selecting - photos. You must specify it.
- .innerJoinAndSelect("photo.metadata", "metadata")
- .leftJoinAndSelect("photo.albums", "album")
- .where("photo.isPublished = true")
- .andWhere("(photo.name = :photoName OR photo.name = :bearName)")
- .orderBy("photo.id", "DESC")
- .skip(5)
- .take(10)
- .setParameters({ photoName: "My", bearName: "Mishka" })
- .getMany()
- ```