ORM for TypeScript and JavaScript (ES7, ES6, ES5). Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, SAP Hana, WebSQL databases. Works in NodeJS, Browser, Ionic, Cordova and Electron platforms.

Overview

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 (ES5, ES6, ES7, ES8). Its goal is to always support the latest JavaScript features and provide additional features 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 and Data Mapper patterns, unlike all other JavaScript ORMs currently in existence, which means you can write high quality, loosely coupled, scalable, maintainable applications the most productive way.

TypeORM is highly influenced by other ORMs, such as Hibernate, Doctrine and Entity Framework.

Features

  • supports both DataMapper and ActiveRecord (your choice)
  • entities and columns
  • database-specific column types
  • entity manager
  • repositories and custom repositories
  • clean object relational model
  • associations (relations)
  • eager and lazy relations
  • uni-directional, bi-directional and self-referenced relations
  • supports multiple inheritance patterns
  • cascades
  • indices
  • transactions
  • migrations and automatic migrations generation
  • connection pooling
  • replication
  • using multiple database connections
  • working with multiple databases types
  • cross-database and cross-schema queries
  • elegant-syntax, flexible and powerful QueryBuilder
  • left and inner joins
  • proper pagination for queries using joins
  • query caching
  • streaming raw results
  • logging
  • listeners and subscribers (hooks)
  • supports closure table pattern
  • schema declaration in models or separate configuration files
  • connection configuration in json / xml / yml / env formats
  • supports MySQL / MariaDB / Postgres / CockroachDB / SQLite / Microsoft SQL Server / Oracle / SAP Hana / sql.js
  • supports MongoDB NoSQL database
  • works in NodeJS / Browser / Ionic / Cordova / React Native / NativeScript / Expo / Electron platforms
  • TypeScript and JavaScript support
  • produced code is performant, flexible, clean and maintainable
  • follows all possible best practices
  • CLI

And more...

With TypeORM your models look like this:

import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";

@Entity()
export class User {

    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    firstName: string;

    @Column()
    lastName: string;

    @Column()
    age: number;

}

And your domain logic looks like this:

const repository = connection.getRepository(User);

const user = new User();
user.firstName = "Timber";
user.lastName = "Saw";
user.age = 25;
await repository.save(user);

const allUsers = await repository.find();
const firstUser = await repository.findOne(1); // find by id
const timber = await repository.findOne({ firstName: "Timber", lastName: "Saw" });

await repository.remove(timber);

Alternatively, if you prefer to use the ActiveRecord implementation, you can use it as well:

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;

}

And your domain logic will look this way:

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.findOne(1);
const timber = await User.findOne({ firstName: "Timber", lastName: "Saw" });

await timber.remove();

Installation

  1. Install the npm package:

    npm install typeorm --save

  2. You need to install reflect-metadata shim:

    npm install reflect-metadata --save

    and import it somewhere in the global place of your app (for example in app.ts):

    import "reflect-metadata";

  3. You may need to install node typings:

    npm install @types/node --save-dev

  4. Install a database driver:

    • for MySQL or MariaDB

      npm install mysql --save (you can install mysql2 instead as well)

    • for PostgreSQL or CockroachDB

      npm install pg --save

    • for SQLite

      npm install sqlite3 --save

    • for Microsoft SQL Server

      npm install mssql --save

    • for sql.js

      npm install sql.js --save

    • for Oracle

      npm install oracledb --save

      To make the Oracle driver work, you need to follow the installation instructions from their site.

    • for SAP Hana

      npm i @sap/hana-client
      npm i hdb-pool
      

      SAP Hana support made possible by sponsorship of Neptune Software.

    • for MongoDB (experimental)

      npm install mongodb --save

    • for NativeScript, react-native and Cordova

      Check documentation of supported platforms

    Install only one of them, depending on which database you use.

TypeScript configuration

Also, make sure you are using TypeScript version 3.3 or higher, and you have enabled the following settings in tsconfig.json:

"emitDecoratorMetadata": true,
"experimentalDecorators": true,

You may also need to enable es6 in the lib section of compiler options, or install es6-shim from @types.

Quick Start

The quickest way to get started with TypeORM is to use its CLI commands to generate a starter project. Quick start works only if you are using TypeORM in a NodeJS application. If you are using other platforms, proceed to the step-by-step guide.

First, install TypeORM globally:

npm install typeorm -g

Then go to the directory where you want to create a new project and run the command:

typeorm init --name MyProject --database mysql

Where name is the name of your project and database is the database you'll use. Database can be one of the following values: mysql, mariadb, postgres, cockroachdb, sqlite, mssql, oracle, mongodb, cordova, react-native, expo, nativescript.

This command will generate a new project in the MyProject directory with the following files:

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
│   └── index.ts     // start point of your application
├── .gitignore       // standard gitignore file
├── ormconfig.json   // ORM and database connection configuration
├── 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.

The next step is to install new project dependencies:

cd MyProject
npm install

While installation is in progress, edit the ormconfig.json file and put your own database connection configuration options in there:

{
   "type": "mysql",
   "host": "localhost",
   "port": 3306,
   "username": "test",
   "password": "test",
   "database": "test",
   "synchronize": true,
   "logging": false,
   "entities": [
      "src/entity/**/*.ts"
   ],
   "migrations": [
      "src/migration/**/*.ts"
   ],
   "subscribers": [
      "src/subscriber/**/*.ts"
   ]
}

Particularly, most of the time you'll only need to configure host, username, password, database and maybe port options.

Once you finish with configuration and all node modules are installed, you can run your application:

npm start

That's it, your application should successfully run and insert a new user into the database. You can continue to work with this project and integrate other modules you need and start creating more entities.

You can generate an even more advanced project with express installed by running typeorm init --name MyProject --database mysql --express command.

You can generate docker-compose file by running typeorm init --name MyProject --database postgres --docker command.

Step-by-Step Guide

What are you expecting from ORM? First of all, you are expecting it will create database tables for you and find / insert / update / delete your data without the pain of having to write lots of hardly maintainable SQL queries. This guide will show you how to setup TypeORM from scratch and make it do what you are expecting from an ORM.

Create a model

Working with a database starts from creating tables. How do you tell TypeORM to create a database table? The answer is - through the models. Your models in your app are your database tables.

For example, you have a Photo model:

export class Photo {
    id: number;
    name: string;
    description: string;
    filename: string;
    views: number;
    isPublished: boolean;
}

And you want to store photos in your database. To store things in the database, first you need a database table, and database tables are created from your models. Not all models, but only those you define as entities.

Create an entity

Entity is your model decorated by an @Entity decorator. A database table will be created for such models. You work with entities everywhere with TypeORM. You can load/insert/update/remove and perform other operations with them.

Let's make our Photo model as an entity:

import { Entity } from "typeorm";

@Entity()
export class Photo {
    id: number;
    name: string;
    description: string;
    filename: string;
    views: number;
    isPublished: boolean;
}

Now, a database table will be created for the Photo entity and we'll be able to work with it anywhere in our app. We have created a database table, however what table can exist without columns? Let's create a few columns in our database table.

Adding table columns

To add database columns, you simply need to decorate an entity's properties you want to make into a column with a @Column decorator.

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;
}

Now id, name, description, filename, views and isPublished columns will be added to the photo table. Column types in the database are inferred from the property types you used, e.g. number will be converted into integer, string into varchar, boolean into bool, etc. But you can use any column type your database supports by explicitly specifying a column type into the @Column decorator.

We generated a database table with columns, but there is one thing left. Each database table must have a column with a primary key.

Creating a primary column

Each entity must have at least one primary key column. This is a requirement and you can't avoid it. To make a column a primary key, you need to use @PrimaryColumn decorator.

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

Now, let's say you want your id column to be auto-generated (this is known as auto-increment / sequence / serial / generated identity column). To do that, you need to change the @PrimaryColumn decorator to a @PrimaryGeneratedColumn decorator:

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

Next, let's fix our data types. By default, string is mapped to a varchar(255)-like type (depending on the database type). Number is mapped to a integer-like type (depending on the database type). We don't want all our columns to be limited varchars or integers. Let's setup correct data types:

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;
}

Column types are database-specific. You can set any column type your database supports. More information on supported column types can be found here.

Creating a connection to the database

Now, when our entity is created, let's create an index.ts (or app.ts whatever you call it) file and set up our connection there:

import "reflect-metadata";
import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";

createConnection({
    type: "mysql",
    host: "localhost",
    port: 3306,
    username: "root",
    password: "admin",
    database: "test",
    entities: [
        Photo
    ],
    synchronize: true,
    logging: false
}).then(connection => {
    // here you can start to work with your entities
}).catch(error => console.log(error));

We are using MySQL in this example, but you can use any other supported database. To use another database, simply change the type in the options to the database type you are using: mysql, mariadb, postgres, cockroachdb, sqlite, mssql, oracle, cordova, nativescript, react-native, expo, or mongodb. Also make sure to use your own host, port, username, password and database settings.

We added our Photo entity to the list of entities for this connection. Each entity you are using in your connection must be listed there.

Setting synchronize makes sure your entities will be synced with the database, every time you run the application.

Loading all entities from the directory

Later, when we create more entities we need to add them to the entities in our configuration. This is not very convenient, so instead we can set up the whole directory, from where all entities will be connected and used in our connection:

import { createConnection } from "typeorm";

createConnection({
    type: "mysql",
    host: "localhost",
    port: 3306,
    username: "root",
    password: "admin",
    database: "test",
    entities: [
        __dirname + "/entity/*.js"
    ],
    synchronize: true,
}).then(connection => {
    // here you can start to work with your entities
}).catch(error => console.log(error));

But be careful with this approach. If you are using ts-node then you need to specify paths to .ts files instead. If you are using outDir then you'll need to specify paths to .js files inside outDir directory. If you are using outDir and when you remove or rename your entities make sure to clear outDir directory and re-compile your project again, because when you remove your source .ts files their compiled .js versions aren't removed from output directory and still are loaded by TypeORM because they are present in the outDir directory.

Running the application

Now if you run your index.ts, a connection with database will be initialized and a database table for your photos will be created.

+-------------+--------------+----------------------------+
|                         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

Now let's create a new photo to save it in the database:

import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";

createConnection(/*...*/).then(connection => {

    let 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;

    return connection.manager
            .save(photo)
            .then(photo => {
                console.log("Photo has been saved. Photo id is", photo.id);
            });

}).catch(error => console.log(error));

Once your entity is saved it will get a newly generated id. save method returns an instance of the same object you pass to it. It's not a new copy of the object, it modifies its "id" and returns it.

Using async/await syntax

Let's take advantage of the latest ES8 (ES2017) features and use async/await syntax instead:

import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";

createConnection(/*...*/).then(async connection => {

    let 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 connection.manager.save(photo);
    console.log("Photo has been saved");

}).catch(error => console.log(error));

Using Entity Manager

We just created a new photo and saved it in the database. We used EntityManager to save it. Using entity manager you can manipulate any entity in your app. For example, let's load our saved entity:

import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";

createConnection(/*...*/).then(async connection => {

    /*...*/
    let savedPhotos = await connection.manager.find(Photo);
    console.log("All photos from the db: ", savedPhotos);

}).catch(error => console.log(error));

savedPhotos will be an array of Photo objects with the data loaded from the database.

Learn more about EntityManager here.

Using Repositories

Now let's refactor our code and use Repository instead of EntityManager. Each entity has its own repository which handles all operations with its entity. When you deal with entities a lot, Repositories are more convenient to use than EntityManagers:

import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";

createConnection(/*...*/).then(async connection => {

    let 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;

    let photoRepository = connection.getRepository(Photo);

    await photoRepository.save(photo);
    console.log("Photo has been saved");

    let savedPhotos = await photoRepository.find();
    console.log("All photos from the db: ", savedPhotos);

}).catch(error => console.log(error));

Learn more about Repository here.

Loading from the database

Let's try more load operations using the Repository:

import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";

createConnection(/*...*/).then(async connection => {

    /*...*/
    let allPhotos = await photoRepository.find();
    console.log("All photos from the db: ", allPhotos);

    let firstPhoto = await photoRepository.findOne(1);
    console.log("First photo from the db: ", firstPhoto);

    let meAndBearsPhoto = await photoRepository.findOne({ name: "Me and Bears" });
    console.log("Me and Bears photo from the db: ", meAndBearsPhoto);

    let allViewedPhotos = await photoRepository.find({ views: 1 });
    console.log("All viewed photos: ", allViewedPhotos);

    let allPublishedPhotos = await photoRepository.find({ isPublished: true });
    console.log("All published photos: ", allPublishedPhotos);

    let [allPhotos, photosCount] = await photoRepository.findAndCount();
    console.log("All photos: ", allPhotos);
    console.log("Photos count: ", photosCount);

}).catch(error => console.log(error));

Updating in the database

Now let's load a single photo from the database, update it and save it:

import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";

createConnection(/*...*/).then(async connection => {

    /*...*/
    let photoToUpdate = await photoRepository.findOne(1);
    photoToUpdate.name = "Me, my friends and polar bears";
    await photoRepository.save(photoToUpdate);

}).catch(error => console.log(error));

Now photo with id = 1 will be updated in the database.

Removing from the database

Now let's remove our photo from the database:

import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";

createConnection(/*...*/).then(async connection => {

    /*...*/
    let photoToRemove = await photoRepository.findOne(1);
    await photoRepository.remove(photoToRemove);

}).catch(error => console.log(error));

Now photo with id = 1 will be removed from the database.

Creating a one-to-one relation

Let's create a one-to-one relation with another class. Let's create a new class in PhotoMetadata.ts. This PhotoMetadata class is supposed to contain our photo's additional meta-information:

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(type => Photo)
    @JoinColumn()
    photo: Photo;
}

Here, we are using a new decorator called @OneToOne. It allows us to create a one-to-one relationship between two entities. type => Photo is a function that returns the class of the entity with which we want to make our relationship. We are forced to use a function that returns a class, instead of using the class directly, because of the language specifics. We can also write it as () => Photo, but we use type => Photo as a convention to increase code readability. The type variable itself does not contain anything.

We also add a @JoinColumn decorator, which indicates that this side of the relationship will own the relationship. Relations can be unidirectional or bidirectional. Only one side of relational can be owning. Using @JoinColumn decorator is required on the owner side of the relationship.

If you run the app, you'll see a newly generated table, and it will contain a column with a foreign key for the photo relation:

+-------------+--------------+----------------------------+
|                     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

Now let's save a photo, its metadata and attach them to each other.

import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";
import { PhotoMetadata } from "./entity/PhotoMetadata";

createConnection(/*...*/).then(async connection => {

    // create a photo
    let 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 a photo metadata
    let 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
    let photoRepository = connection.getRepository(Photo);
    let metadataRepository = connection.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 relation between metadata and photo is created in the database too");

}).catch(error => console.log(error));

Inverse side of the relationship

Relations can be unidirectional or bidirectional. Currently, our relation between PhotoMetadata and Photo is unidirectional. The owner of the relation is PhotoMetadata, and Photo doesn't know anything about PhotoMetadata. This makes it complicated to access PhotoMetadata from the Photo side. To fix this issue we should add an inverse relation, and make relations between PhotoMetadata and Photo bidirectional. Let's modify our entities:

import { Entity, Column, PrimaryGeneratedColumn, OneToOne, JoinColumn } from "typeorm";
import { Photo } from "./Photo";

@Entity()
export class PhotoMetadata {

    /* ... other columns */

    @OneToOne(type => Photo, photo => photo.metadata)
    @JoinColumn()
    photo: Photo;
}
import { Entity, Column, PrimaryGeneratedColumn, OneToOne } from "typeorm";
import { PhotoMetadata } from "./PhotoMetadata";

@Entity()
export class Photo {

    /* ... other columns */

    @OneToOne(type => PhotoMetadata, photoMetadata => photoMetadata.photo)
    metadata: PhotoMetadata;
}

photo => photo.metadata is a function that returns the name of the inverse side of the relation. Here we show that the metadata property of the Photo class is where we store PhotoMetadata in the Photo class. Instead of passing a function that returns a property of the photo, you could alternatively simply pass a string to @OneToOne decorator, like "metadata". But we used this function-typed approach to make our refactoring easier.

Note that we should use @JoinColumn decorator only on one side of a relation. Whichever side you put this decorator on will be the owning side of the relationship. The owning side of a relationship contains a column with a foreign key in the database.

Loading objects with their relations

Now let's load our photo and its photo metadata in a single query. There are two ways to do it - using find* methods or using QueryBuilder functionality. Let's use find* methods first. find* methods allow you to specify an object with the FindOneOptions / FindManyOptions interface.

import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";
import { PhotoMetadata } from "./entity/PhotoMetadata";

createConnection(/*...*/).then(async connection => {

    /*...*/
    let photoRepository = connection.getRepository(Photo);
    let photos = await photoRepository.find({ relations: ["metadata"] });

}).catch(error => console.log(error));

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.

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:

import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";
import { PhotoMetadata } from "./entity/PhotoMetadata";

createConnection(/*...*/).then(async connection => {

    /*...*/
    let photos = await connection
            .getRepository(Photo)
            .createQueryBuilder("photo")
            .innerJoinAndSelect("photo.metadata", "metadata")
            .getMany();


}).catch(error => console.log(error));

QueryBuilder allows creation and execution of SQL queries of almost any complexity. When you work with QueryBuilder, think like you are creating an SQL query. In this example, "photo" and "metadata" are aliases applied to selected photos. You use aliases to access columns and properties of the selected data.

Using cascades to automatically save related objects

We can setup cascade options in our relations, in the cases when we want our related object to be saved whenever the other object is saved. Let's change our photo's @OneToOne decorator a bit:

export class Photo {
    /// ... other columns

    @OneToOne(type => PhotoMetadata, metadata => metadata.photo, {
        cascade: true,
    })
    metadata: PhotoMetadata;
}

Using cascade allows us not to separately save photo and separately save metadata objects now. Now we can simply save a photo object, and the metadata object will be saved automatically because of cascade options.

createConnection(options).then(async connection => {

    // create photo object
    let 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
    let 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
    let photoRepository = connection.getRepository(Photo);

    // saving a photo also save the metadata
    await photoRepository.save(photo);

    console.log("Photo is saved, photo metadata is saved too.")

}).catch(error => console.log(error));

Notice that we now set the photo's metadata property, instead of the metadata's photo property as before. The cascade feature only works if you connect the photo to its metadata from the photo's side. If you set the metadata's side, the metadata would not be saved automatically.

Creating a many-to-one / one-to-many relation

Let's create a many-to-one / one-to-many relation. Let's say a photo has one author, and each author can have many photos. First, let's create an Author class:

import { Entity, Column, PrimaryGeneratedColumn, OneToMany, JoinColumn } from "typeorm";
import { Photo } from "./Photo";

@Entity()
export class Author {

    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    name: string;

    @OneToMany(type => Photo, photo => photo.author) // note: we will create author property in the Photo class below
    photos: Photo[];
}

Author contains an inverse side of a relation. OneToMany is always an inverse side of relation, and it can't exist without ManyToOne on the other side of the relation.

Now let's add the owner side of the relation into the Photo entity:

import { Entity, Column, PrimaryGeneratedColumn, ManyToOne } from "typeorm";
import { PhotoMetadata } from "./PhotoMetadata";
import { Author } from "./Author";

@Entity()
export class Photo {

    /* ... other columns */

    @ManyToOne(type => Author, author => author.photos)
    author: Author;
}

In many-to-one / one-to-many relation, the owner side is always many-to-one. It means that the class that uses @ManyToOne will store the id of the related object.

After you run the application, the ORM will create the author table:

+-------------+--------------+----------------------------+
|                          author                         |
+-------------+--------------+----------------------------+
| id          | int(11)      | PRIMARY KEY AUTO_INCREMENT |
| name        | varchar(255) |                            |
+-------------+--------------+----------------------------+

It will also modify the photo table, adding a new author column and creating a foreign key for it:

+-------------+--------------+----------------------------+
|                         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

Let's create a many-to-one / many-to-many relation. Let's say a photo can be in many albums, and each album can contain many photos. Let's create an Album class:

import { Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable } from "typeorm";

@Entity()
export class Album {

    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    name: string;

    @ManyToMany(type => Photo, photo => photo.albums)
    @JoinTable()
    photos: Photo[];
}

@JoinTable is required to specify that this is the owner side of the relationship.

Now let's add the inverse side of our relation to the Photo class:

export class Photo {
    /// ... other columns

    @ManyToMany(type => Album, album => album.photos)
    albums: Album[];
}

After you run the application, the ORM will create a album_photos_photo_albums junction table:

+-------------+--------------+----------------------------+
|                album_photos_photo_albums                |
+-------------+--------------+----------------------------+
| album_id    | int(11)      | PRIMARY KEY FOREIGN KEY    |
| photo_id    | int(11)      | PRIMARY KEY FOREIGN KEY    |
+-------------+--------------+----------------------------+

Don't forget to register the Album class with your connection in the ORM:

const options: ConnectionOptions = {
    // ... other options
    entities: [Photo, PhotoMetadata, Author, Album]
};

Now let's insert albums and photos to our database:

let connection = await createConnection(options);

// create a few albums
let album1 = new Album();
album1.name = "Bears";
await connection.manager.save(album1);

let album2 = new Album();
album2.name = "Me";
await connection.manager.save(album2);

// create a few photos
let 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 connection.manager.save(photo);

// now our photo is saved and albums are attached to it
// now lets load them:
const loadedPhoto = await connection
    .getRepository(Photo)
    .findOne(1, { relations: ["albums"] });

loadedPhoto will be equal to:

{
    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

You can use QueryBuilder to build SQL queries of almost any complexity. For example, you can do this:

let photos = await connection
    .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();

This query selects all published photos with "My" or "Mishka" names. It will select results from position 5 (pagination offset), and will select only 10 results (pagination limit). The selection result will be ordered by id in descending order. The photo's 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.

Samples

Take a look at the samples in sample for examples of usage.

There are a few repositories which you can clone and start with:

Extensions

There are several extensions that simplify working with TypeORM and integrating it with other modules:

Contributing

Learn about contribution here and how to setup your development environment here.

This project exists thanks to all the people who contribute:

Sponsors

Open source is hard and time-consuming. If you want to invest into TypeORM's future you can become a sponsor and allow our core team to spend more time on TypeORM's improvements and new features. Become a sponsor

Gold Sponsors

Become a gold sponsor and get a premium technical support from our core contributors. Become a gold sponsor

Comments
  • Feat/soft delete

    Feat/soft delete

    1. added @DeleteDateColumn
    2. added the softDelete and restore methods to query builder
    3. added the softDelete and restore methods to repository
    4. added the softRemove and recover methods to repository
    5. added the support of the cascades soft-remove and recover
    opened by iWinston 80
  • LINQ-style query builder

    LINQ-style query builder

    First I'd like to say this is an Impressive framework!

    Back on topic, I assume you have considered a more functional (rather than string-based) querying mechanism (like LINQ to SQL). What are the limitations and/or difficulty of implementing something like that?

    discussion 
    opened by srolel 80
  • Allow WHERE clause on joined columns.

    Allow WHERE clause on joined columns.

    Issue type:

    [ ] question [ ] bug report [x ] feature request [ ] documentation issue

    Hi!

    As it said in the documentation of FindManyOptions#where:

    Querying a column from an embedded entity should be done with respect to the hierarchy in which it was defined.

    It is possible to extend this capability to the joined columns ?

    For exemple with 2 entities:

    @Entity()
    class Contact {
      @PrimaryGeneratedColumn()
      id: number;
      @Column()
      name: string;
      @ManyToOne(type => Address)
      address: Address;
    }
    
    class Address {
      @PrimaryGeneratedColumn()
      id: number;
      @Column()
      street: string;
      @Column()
      city: string;
    }
    

    Make a request like this:

    contactRepository.find({
      relations: [ 'address' ],
      where: {
        address: {
          city: 'Paris'
        }
      }
    });
    

    SQL:

    SELECT `Contact`.`id` AS `Contact_id`
        `Contact`.`id` AS `Contact_id`
        `Contact`.`name` AS `Contact_name`
        `Contact`.`addressId` AS `Contact_addressId`
        `Contact_address`.`id` AS `Contact_address_id`
        `Contact_address`.`street` AS `Contact_address_street`
        `Contact_address`.`city` AS `Contact_address_city`
      FROM `contact` `Contact`
      LEFT JOIN `address` `Contact_address`
        ON `Contact_address`.`id` = `Contact`.`addressId`
      WHERE `Contact_address`.`city` = "Paris";
    

    I don't have seen any other options in TypeORM documentation to apply where clauses on joined columns. If there another way I am interested about it.

    Thank you in advance for your help.

    new feature comp: query builder comp: find options 
    opened by Techniv 72
  • Error: Entity metadata was not found

    Error: Entity metadata was not found

    // conversation_pairs.ts
    
    @Entity()
    export class ConversationPairs {
    
      @PrimaryGeneratedColumn()
      id: number;
    
      @ManyToOne(type => Users, user_id => user_id.conversation_pairs, {
        cascadeRemove: true,
        nullable: false
      })
      user_id: Users;
    
      @ManyToOne(type => Agents, agent_id => agent_id.conversation_pairs, {
        cascadeRemove: true,
        nullable: false
      })
      agent_id: Agents;
    }
    
    // user.ts
    
    @Entity()
    export class Users {
      @PrimaryGeneratedColumn()
      id: number;
    
      @OneToMany(type => ConversationPairs, conversation_pairs => conversation_pairs.user_id)
      conversation_pairs: ConversationPairs[];
    }
    
    // agent.ts
    
    @Entity()
    export class Agents {
    
      @PrimaryGeneratedColumn()
      id: number;
    
      @OneToMany(type => ConversationPairs, conversation_pairs => conversation_pairs.agent_id)
      conversation_pairs: ConversationPairs[];
    }
    
    

    I have these 3 files and getting this error when I start my app.

    Error: Entity metadata for ConversationPairs#user_id was not found.
        at /Users/xuanrong/Sites/calllevels/dbs-chat/node_modules/typeorm/metadata-builder/EntityMetadataBuilder.js:272:27
        at Array.forEach (native)
        at /Users/xuanrong/Sites/calllevels/dbs-chat/node_modules/typeorm/metadata-builder/EntityMetadataBuilder.js:269:38
        at Array.forEach (native)
        at EntityMetadataBuilder.build (/Users/xuanrong/Sites/calllevels/dbs-chat/node_modules/typeorm/metadata-builder/EntityMetadataBuilder.js:268:25)
        at EntityMetadataBuilder.buildFromMetadataArgsStorage (/Users/xuanrong/Sites/calllevels/dbs-chat/node_modules/typeorm/metadata-builder/EntityMetadataBuilder.js:152:21)
        at Connection.buildMetadatas (/Users/xuanrong/Sites/calllevels/dbs-chat/node_modules/typeorm/connection/Connection.js:552:18)
        at Connection.<anonymous> (/Users/xuanrong/Sites/calllevels/dbs-chat/node_modules/typeorm/connection/Connection.js:174:30)
        at step (/Users/xuanrong/Sites/calllevels/dbs-chat/node_modules/typeorm/connection/Connection.js:32:23)
        at Object.next (/Users/xuanrong/Sites/calllevels/dbs-chat/node_modules/typeorm/connection/Connection.js:13:53)
    

    Not sure what to do, need some help on this.

    opened by zxr90 66
  • .findOne(undefined) returns first item in the database instead of undefined

    .findOne(undefined) returns first item in the database instead of undefined

    Issue type:

    [ ] question [x] bug report [ ] feature request [ ] documentation issue

    Database system/driver:

    [ ] cordova [ ] mongodb [ ] mssql [ ] mysql / mariadb [ ] oracle [x ] postgres [ ] sqlite [ ] sqljs [ ] react-native [ ] expo

    TypeORM version:

    [x] latest [ ] @next [ ] 0.x.x (or put your version here)

    Steps to reproduce or a small repository showing the problem:

    user.id = undefined;
    User.findOne(user.id); // expect to see undefined / null but returns the first item in the table
    
    discussion comp: find options 
    opened by ct-reposit 62
  • [serverless] Connection Reuse is broken in a Lambda environment

    [serverless] Connection Reuse is broken in a Lambda environment

    Issue type:

    [ ] question [x] bug report [ ] feature request [ ] documentation issue

    Database system/driver:

    [ ] cordova [ ] mongodb [ ] mssql [ ] mysql / mariadb [ ] oracle [x] postgres [ ] sqlite [ ] sqljs [ ] react-native [ ] expo

    TypeORM version:

    [x] latest [ ] @next [ ] 0.x.x (or put your version here)

    Steps to reproduce or a small repository showing the problem:

    I'm primarily expanding further on https://github.com/typeorm/typeorm/issues/2598#issue-345445322, the fixes described there are catastrophic in nature, because:

    1. They either involve closing connections without understanding that the lambda may not just be serving that one request.
    2. Full bootstrap of the connection a second time anyway (defeating the purpose of caching it in the first place)) and I believe this is something that should be addressed in core.
    3. Even the somewhat saner metadata rebuild causes problems (since it cannot be awaited and runs in parallel). This results in metadata lookups while queries are running (for another controller, perhaps) randomly start failing.

    The issue is exactly as described, if we attempt to reuse connections in a lambda environment, the entity manager no longer seems to know anything about our entities.

    The first request made completes successfully (and primes our connection manager to reuse the same connection). Subsequent requests quit with RepositoryNotFoundError: No repository for "TData" was found. Looks like this entity is not registered in current "default" connection?

    Here's a complete test case (with no external dependencies other than typeorm and uuid): https://gist.github.com/Wintereise/3d59a0414419b4ecca5137c20fc29622

    When the else block (line #22 onwards) is hit, all is well, things work fine. When the cached connection from manager.get("default") is hit however, we can no longer run queries.

    If it's needed, I can setup a project with serverless-offline for click-and-go testing.

    bug driver: postgres 
    opened by Wintereise 59
  • How can I sort relations loaded with find's

    How can I sort relations loaded with find's "relations" option?

    Issue type:

    [X] question [ ] bug report [ ] feature request [ ] documentation issue

    Database system/driver:

    [ ] cordova [ ] mongodb [ ] mssql [ ] mysql / mariadb [ ] oracle [X] postgres [ ] sqlite [ ] sqljs [ ] react-native [ ] expo

    TypeORM version:

    [X] latest [ ] @next [ ] 0.x.x (or put your version here)

    Steps to reproduce or a small repository showing the problem:

    I'm loading an entity with a one-to-many relationship. So, that relationship is an array of entities associated with the entity I'm querying. I'd like to specify an order for that array of entities.

    Example (Users and their Photos): I'd like to query a user, load their photos as a relation, and the photos should be loaded by their createdAt date:

    const users = await this.usersRepository.findOne(conditions, {
          relations: ['photos'],
          order: {
            // Just getting one user, but  the photos should be ordered in 'DESC' by 'photos.createdAt'
          },
        });
    

    Is there a way to do this?

    question comp: relations driver: postgres comp: find options 
    opened by kodayashi 58
  • Nested relations filtering doesn't work

    Nested relations filtering doesn't work

    Issue type:

    [ ] question [x] bug report [ ] feature request [ ] documentation issue

    TypeORM version:

    [ ] latest [ ] @next [x] 0.2.15 (or put your version here)

    Steps to reproduce or a small repository showing the problem:

    I have 2 models

    category.entity.ts

    @Entity()
    export class BlogCategoryEntity {
      @PrimaryGeneratedColumn()
      id: number;
    
      @Index()
      @Column({unique: true})
      alias: string;
    
      @Column()
      title: string;
    
      @OneToMany(type => BlogPostEntity, post => post.category)
      posts: BlogPostEntity[]
    }
    

    post.entity.js

    @Entity()
    export class BlogPostEntity {
      @PrimaryGeneratedColumn()
      id: number;
    
      @Index()
      @Column({unique: true})
      alias: string;
    
      @Column()
      title: string;
    
      @Column('text')
      description: string;
    
      @Column({type: 'text', nullable: true})
      text: string;
    
      @Index()
      @Column()
      isPublished: boolean;
    
      @Index()
      @Column()
      publishedAt: Date;
    
      @Column()
      categoryId: number;
    
      @ManyToOne(type => BlogCategoryEntity, category => category.posts, {eager: true, nullable: false, onDelete: 'CASCADE'})
      @JoinColumn()
      category: BlogCategoryEntity;
    }
    

    When i filter query by category_id, everything is ok:

    const [rows, count] = await this.repository.findAndCount({
      skip: query.skip,
      take: query.take,
      where: {
        category: {
          id: 1
        }
      }
    });
    

    But, filter works only by primary nested field. Filtering by other fields don't work:

    const [rows, count] = await this.repository.findAndCount({
      skip: query.skip,
      take: query.take,
      where: {
        category: {
          alias: 'test'
        }
      }
    });
    
    SELECT
      "BlogPostEntity"."id" AS "BlogPostEntity_id",
      "BlogPostEntity"."alias" AS "BlogPostEntity_alias",
      "BlogPostEntity"."title" AS "BlogPostEntity_title",
      "BlogPostEntity"."description" AS "BlogPostEntity_description",
      "BlogPostEntity"."text" AS "BlogPostEntity_text",
      "BlogPostEntity"."isPublished" AS "BlogPostEntity_isPublished",
      "BlogPostEntity"."publishedAt" AS "BlogPostEntity_publishedAt",
      "BlogPostEntity"."categoryId" AS "BlogPostEntity_categoryId",
      "BlogPostEntity_category"."id" AS "BlogPostEntity_category_id",
      "BlogPostEntity_category"."alias" AS "BlogPostEntity_category_alias",
      "BlogPostEntity_category"."title" AS "BlogPostEntity_category_title"
    FROM "blog_post_entity" "BlogPostEntity"
    LEFT JOIN "blog_category_entity" "BlogPostEntity_category"
      ON "BlogPostEntity_category"."id"="BlogPostEntity"."categoryId"
    WHERE "BlogPostEntity"."categoryId" = ? -- PARAMETERS: [null]
    

    Are there options to implement this?

    bug comp: find options 
    opened by trixden 56
  • .save() is throwing duplicate key value violates unique constraint

    .save() is throwing duplicate key value violates unique constraint

    Issue type:

    [x] question [ ] bug report [ ] feature request [ ] documentation issue

    Database system/driver:

    [ ] cordova [ ] mongodb [ ] mssql [ ] mysql / mariadb [ ] oracle [x] postgres [ ] cockroachdb [ ] sqlite [ ] sqljs [ ] react-native [ ] expo

    TypeORM version:

    [x] latest [ ] @next [ ] 0.x.x (or put your version here)

    This was working for me earlier but now it is not. I am using a composite key of three different properties. Every time I try to update and existing row, I get the error QueryFailedError: duplicate key value violates unique constraint "PK_8b1375852f33d30b328388e5a5c".

    This is my entity:

    'use strict';
    
    import * as _ from 'lodash';
    import { Entity, Column, PrimaryColumn, Generated } from "typeorm";
    
    
    @Entity()
    export class Assortment {
    
    	@Column("uuid")
    	@Generated("uuid")
    	id!: string;
    
    	@PrimaryColumn()
    	accountId!: string;
    
    	@PrimaryColumn()
    	entityType!: string;
    
    	@PrimaryColumn()
    	parentId!: string;
    
    	@Column({
    		nullable: true
    	})
    	parentType!: string;
    
    	@Column('varchar', {
    		nullable: true
    	})
    	sortedIds!: string[];
    
    	@Column('jsonb', {
    		nullable: true
    	})
    	children!: Assortment[];
    };
    
    question driver: postgres 
    opened by W0lfbane 54
  • [question] migration cannot recongnize keyword `import`?

    [question] migration cannot recongnize keyword `import`?

    After setting up ormconfig.json, I use typeorm migrations:create -n base to create migration file. But when I run typeorm migrations:run, it seems cannot recognize the key word import.

    ormconfig.json

    {
        "type": "mysql",
        "host": "localhost",
        "port": 3306,
        "username": "dinfer",
        "password": "dinfer",
        "database": "haodf",
        "logging": {
            "logOnlyFailedQueries": true
        },
        "autoSchemaSync": false,
        "migrations": [
            "src/models/migrations/*.ts"
        ],
        "cli": {
            "migrationsDir": "src/models/migrations"
        }
    }
    

    the migration script

    import { ColumnSchema, MigrationInterface, QueryRunner, TableSchema } from 'typeorm';
    
    export class IncreaseDoctorSkillLength1501091244552 implements MigrationInterface {
    
        public async up(queryRunner: QueryRunner): Promise<any> {
            await queryRunner.createTable(new TableSchema('a', [
                new ColumnSchema({ name: 't', type: 'string', length: 1000 })
            ]))
        }
    
        public async down(queryRunner: QueryRunner): Promise<any> {
            await queryRunner.dropTable('a')
        }
    
    }
    

    the output

    Error during migration run:
    E:\crawler\spider\src\models\migrations\1501091244552-base.ts:1
    (function (exports, require, module, __filename, __dirname) { import { ColumnSchema, MigrationInterface, QueryRunner, TableSchema } from 'typeorm';
                                                                  ^^^^^^
    
    SyntaxError: Unexpected token import
        at createScript (vm.js:74:10)
        at Object.runInThisContext (vm.js:116:10)
        at Module._compile (module.js:533:28)
        at Object.Module._extensions..js (module.js:580:10)
        at Module.load (module.js:503:32)
        at tryModuleLoad (module.js:466:12)
        at Function.Module._load (module.js:458:3)
        at Module.require (module.js:513:17)
        at require (internal/module.js:11:18)
        at Function.PlatformTools.load (C:\Users\dinfer\AppData\Roaming\npm\node_modules\typeorm\platform\PlatformTools.js:28:20)
    PS E:\work\crawler\spider>
    

    tsconfig.json

    {
      "compilerOptions": {
        "target": "es2017",
        "module": "commonjs",
        "rootDir": "./src",
        "strict": true,
        "experimentalDecorators": true, 
        "emitDecoratorMetadata": true
      }
    }
    
    

    npm ls -g --depth=0

    +-- [email protected]
    
    question 
    opened by dinfer 54
  • @TypeORM splitting drivers into separate packages

    @TypeORM splitting drivers into separate packages

    I was thinking a lot how to solve all problems with new differing drivers like mongodb one. Solution is to separate packages:

    • @typeorm/mysql
    • @typeorm/mariadb
    • @typeorm/sqlite
    • @typeorm/sql-server
    • @typeorm/oracle
    • @typeorm/websql
    • @typeorm/mongodb

    and possible future drivers like:

    • @typeorm/redis
    • @typeorm/elasticsearch
    • @typeorm/cassandra
    • @typeorm/rethinkdb
    • @typeorm/neo4j

    etc.

    This requires lot of refactoring efforts and increases orm complexity, but that seems the only way to go further with different driver types.

    We may also have general packages like @typeorm/core, @typeorm/sql, @typeorm/nosql however I'm not sure about them. Alternatively we can simply pack everything needed into their packages using different build scripts and tsconfigs.

    Also another solution is to have @typeorm/typeorm and everything go from there, other packages just use declaration merging ability of TypeScript and add additional functionality, and users just use single @typeorm/typeorm namespace everywhere.

    Need help - suggestions, proposals or coding help if possible.

    help wanted discussion 
    opened by pleerock 52
  • Incorrect enum default value when table name contains dash character

    Incorrect enum default value when table name contains dash character

    Issue description

    typeorm not able to load proper default value of enum column type when the table name has a dash

    Expected Behavior

    While generating a migration script, if the enum column hasn't changed, Typeorm should not create any migration script for that enum column.

    Actual Behavior

    On every migration:generate typescript will recognize the enum default value changed and keep adding up, down scripts to drop enum default value and set again

    Steps to reproduce

    1. Create a table with a name containing a dash like @Entity('module-payment_approval_requests')
    2. Create the first migration file. yarn typeorm --dataSource ./ds.ts migration:generate migrations/intial
    3. Try to run the migration again, yarn typeorm --dataSource ./ds.ts migration:generate migrations/update without any changes
    import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
    
    export enum ApprovalStatus {
      APPROVED = 'APPROVED',
      REJECTED = 'REJECTED',
      PENDING = 'PENDING',
    }
    
    @Entity('module-payment_approval_requests')
    export class ApprovalRequests extends BaseEntity {
      @PrimaryGeneratedColumn('uuid')
      id: string;
    
      @Column({
        type: 'enum',
        enum: ApprovalStatus,
        default: ApprovalStatus.PENDING,
      })
      status: ApprovalStatus;
    }
    
    

    My Environment

    | Dependency | Version | | --- | --- | | Operating System | macOs 13.1 (22C65) | | Node.js version | v18.12.1 | | Typescript version | 4.5.2 | | TypeORM version | 0.3.11 |

    Additional Context

    The problem when trying to regex replace the table name from the default value

    https://github.com/typeorm/typeorm/blob/defb409f5650fed0b7a4ff2933208282a45572fb/src/driver/postgres/PostgresQueryRunner.ts#L3720

    parsing 'UNPAID'::module-payment_order_entity_enum results 'UNPAID'-payment_order_entity_enum" where is supposed to be only UNPAID

    Relevant Database Driver(s)

    • [ ] aurora-mysql
    • [ ] aurora-postgres
    • [ ] better-sqlite3
    • [ ] cockroachdb
    • [ ] cordova
    • [ ] expo
    • [ ] mongodb
    • [ ] mysql
    • [ ] nativescript
    • [ ] oracle
    • [X] postgres
    • [ ] react-native
    • [ ] sap
    • [ ] spanner
    • [ ] sqlite
    • [ ] sqlite-abstract
    • [ ] sqljs
    • [ ] sqlserver

    Are you willing to resolve this issue by submitting a Pull Request?

    Yes, I have the time, and I know how to start.

    bug requires triage 
    opened by KhaledSMQ 0
  • Ability to configure if schema sync or migrations runs first

    Ability to configure if schema sync or migrations runs first

    Feature Description

    on v0.2, schema sync would take place first, and migrations would run after it. In v0.3, that order changed (couldn't find info on the motivation for that).

    Our application relied on schema sync happening first. Our use case is that we use migrations to maintain PostgreSQL stored procedures, so the schema sync would create the tables that the stored procedures would depend on.

    The Solution

    My proposed solution would be to implement some sort of config option that would default to the current v0.3 behavior, but could be configured to instead have the previous behavior

    Considered Alternatives

    An alternative solution would be to manually run the CLI tool to sync the schema, and then start the app (without sync, with migrations), which would respect the necessary order of operations for this particular use case. However, this would effectively require multiple operations to be bundled up (local runs for dev, local test runs, CI runs, etc) with what could be a much more simple solution of setting the right DataSource config values, and letting TypeORM take care of everything automagically.

    Additional Context

    I suspect this affects all db drivers but I'm not sure - happy to run docker tests to ensure everything stays as funky as it is today, after my changes.

    Speaking of which, I am fairly confident I can implement this PR on my own, but don't be too surprised if I ask for some light help/guidance at some point :)

    But before moving forward with this implementation, I would like to know if this is worth investing my time into, aka, if you would consider this valuable to typeorm and its community.

    Relevant Database Driver(s)

    • [ ] aurora-mysql
    • [ ] aurora-postgres
    • [ ] better-sqlite3
    • [ ] cockroachdb
    • [ ] cordova
    • [ ] expo
    • [ ] mongodb
    • [ ] mysql
    • [ ] nativescript
    • [ ] oracle
    • [ ] postgres
    • [ ] react-native
    • [ ] sap
    • [ ] spanner
    • [ ] sqlite
    • [ ] sqlite-abstract
    • [ ] sqljs
    • [ ] sqlserver

    Are you willing to resolve this issue by submitting a Pull Request?

    Yes, I have the time, and I know how to start.

    new feature requires triage 
    opened by tiagojsag 0
  • MissingDriverError: Wrong driver:

    MissingDriverError: Wrong driver: "undefined" given.

    MissingDriverError: Wrong driver: "undefined" given.

    Recommended Fix

    This works in my case:-

    inside app.module.ts imports: [ ConfigModule.forRoot({isGlobal: true}), TypeOrmModule.forRootAsync({ useClass: DatabaseConnectionService //DatabaseConnectionService is the file containing the connection code }) , UserModule ],

    Additional Context

    No response

    Are you willing to resolve this issue by submitting a Pull Request?

    Yes, I have the time, and I know how to start.

    documentation requires triage 
    opened by codingXpert 0
  • Generate Migration on Postgres JSONB Column with Default Value Not Working

    Generate Migration on Postgres JSONB Column with Default Value Not Working

    Issue description

    Generate Migration on Postgres JSONB Column with Default Value Not Working

    Expected Behavior

    I do not expect the column change to show up in migration once I have generated it

    Actual Behavior

    Each time the column comes up with the necessary changes in every single migration

    Steps to reproduce

    I use postgres. I have a column in a table of type jsonb. It is not null and as a default value '{}'::jsonb. The table exists with with non null and default value. Yet, every time I run the migration, this column shows up suggesting changing it to not null and with this default value

    My Environment

    | Dependency | Version | | --- | --- | | Operating System | Linux | | Node.js version | 18.12.1 | | Typescript version | Not getting used | | TypeORM version | 0.3.11 |

    Additional Context

    No response

    Relevant Database Driver(s)

    • [ ] aurora-mysql
    • [ ] aurora-postgres
    • [ ] better-sqlite3
    • [ ] cockroachdb
    • [ ] cordova
    • [ ] expo
    • [ ] mongodb
    • [ ] mysql
    • [ ] nativescript
    • [ ] oracle
    • [X] postgres
    • [ ] react-native
    • [ ] sap
    • [ ] spanner
    • [ ] sqlite
    • [ ] sqlite-abstract
    • [ ] sqljs
    • [ ] sqlserver

    Are you willing to resolve this issue by submitting a Pull Request?

    Yes, I have the time, but I don't know how to start. I would need guidance.

    bug requires triage 
    opened by krushalit 0
  • fix: handles

    fix: handles "query" relation loading strategy for TreeRepositories

    Description of change

    Adds support to loading entities' relationships with "query" strategy for TreeRepositories Previously the default method was "join". Implementation is done recursively for n-level relations

    Closes: #9673

    Pull-Request Checklist

    • [x] Code is up-to-date with the master branch
    • [x] npm run format to apply prettier formatting
    • [x] npm run test passes with this change
    • [x] This pull request links relevant issues as Fixes #0000
    • [x] There are new or updated unit tests validating the change
    • [ ] Documentation has been updated to reflect this change
    • [x] The new commits follow conventions explained in CONTRIBUTING.md
    opened by JoseCToscano 0
  • Using both object relation and relation id (number) breaks saving edited results by causing not-null constraint violation

    Using both object relation and relation id (number) breaks saving edited results by causing not-null constraint violation

    Issue description

    Using both object relation and relation id (number) breaks saving edited results by causing not-null constraint violation

    Actual Behavior

    I have the following entity:

    @Entity()
    class GamePlayerRelationEntity {
      @PrimaryGeneratedColumn()
      public id: number;
    
      @Column({
        type: 'enum',
        enum: GamePlayerRelationType,
        array: true,
        default: [],
        nullable: false,
      })
      public type: GamePlayerRelationType[];
    
      @Column('int', { nullable: true })
      public gameId: number;
    
      @Index()
      @ManyToOne(() => GameEntity, (ge) => ge.players})
      public game: Promise<GameEntity>;
    
      @Column('int')
      public userId: number;
    
      @Index()
      @ManyToOne(() => UserEntity, (user) => user.games, {
        eager: true,
      })
      public user: UserEntity;
    
      @VersionColumn()
      public version: number;
    }
    

    Notice that both relations to User and Game are duplicated, both as object and id. Depending on the service method, I'm using either of them. This works fine when creating a new entity:

        const relation = new GamePlayerRelationEntity();
        relation.game = Promise.resolve(game);
        relation.user = player;
        relation.type = [GamePlayerRelationType.Invited];
        await this.gamePlayerRelationRepository.save(relation);
    

    It fails when I try to edit existing relation:

    const existingRelation = await this.findRelation(gameId, player.id);
    existingRelation.type = [GamePlayerRelationType.Invited];
    await this.gamePlayerRelationRepository.save(existingRelation);
    

    Causes: QueryFailedError: null value in column "gameId" of relation "game_player_relation_entity" violates not-null constraint

    When I check existingRelation, it has gameId filled in, but not game entity (as expected, as this is not eager relation). I can make it work by doing this:

    const existingRelation = await this.findRelation(gameId, player.id);
    existingRelation.type = [GamePlayerRelationType.Invited];
    existingRelation.game = Promise.resolve({ id: existingRelation.gameId } as GameEntity);
    await this.gamePlayerRelationRepository.save(existingRelation);
    

    The code above saves the entity successfully, but it causes it to update twice (the @Version annotated column increases the number by 2, which causes my Optimistic Locking logic to break); thus, it is not a viable workaround for my use case. Also, reassigning values every time I change something in the entity is not a good developer experience.

    Also, when I added { nullable: true } to both id and entity as a desperate attempt to find a workaround, it caused the relation to becoming null after the update.

    Expected Behavior

    I want to be able to manage relations both by IDs and by assigning Entities at the same time. Both this options should work:

    existingRelation.gameId = gameId;
    await this.gamePlayerRelationRepository.save(existingRelation);
    
    existingRelation.game = Promise.resolve( { id: gameId } as GameEntity);
    await this.gamePlayerRelationRepository.save(existingRelation);
    

    Additionally having both of these assignments should only cause one update (one call for subscribers, one query to DB and one Version column update.

    Steps to reproduce

    As above

    My Environment

    | Dependency | Version | | --- | --- | | Operating System | Windows 10 | | Node.js version | 18.12.1 | | Typescript version | 4.5.5 | | TypeORM version | 0.3.6 |

    Additional Context

    No response

    Relevant Database Driver(s)

    • [ ] aurora-mysql
    • [ ] aurora-postgres
    • [ ] better-sqlite3
    • [ ] cockroachdb
    • [ ] cordova
    • [ ] expo
    • [ ] mongodb
    • [ ] mysql
    • [ ] nativescript
    • [ ] oracle
    • [X] postgres
    • [ ] react-native
    • [ ] sap
    • [ ] spanner
    • [ ] sqlite
    • [ ] sqlite-abstract
    • [ ] sqljs
    • [ ] sqlserver

    Are you willing to resolve this issue by submitting a Pull Request?

    No, I don’t have the time, but I can support (using donations) development.

    bug requires triage 
    opened by vinterdo 0
Releases(0.3.11)
  • 0.3.11(Dec 3, 2022)

    Fixes

    • boolean parameter escape in SQLiteDriver (#9400) (4a36d0e), closes #1981
    • cacheId not used when loading relations with take (#9469) (93e6b3d)
    • correctly return insertId for react-native (#9554) (97fae63)
    • disable transactionSupport option for CordovaDriver (#9391) (53fad8f)
    • explicitly define property for entity relation as enumerable (#9437) (85fa9c6), closes #6631
    • fix ormUtils prototype check crashing on null prototype (#9517) (19536ed)
    • fixed outdated init command (#9422) (0984307)
    • left instead of inner join for where or + optional relations (#9516) (d490793)
    • Mark array arguments to find operators as read-only (#9474) (6eb674b)
    • pass fake flag to undoLastMigration (#9562) (2458ac7), closes #9561
    • resolve issue with migrations and unsigned int columns in aurora-data-api (#9478) (38e0eff), closes #9477
    • resolve nameless TableForeign on drop foreign key (#9460) (efb4168), closes #9432
    • synchronize with typeorm_metadata table only if needed (#9175) (cdabaa3), closes #9173 #9173 #9173
    • the mpath is incorrect when the parent of the tree entity is null (#9535) (658604d)
    • typings for Repository.extend function (#9396) (f07fb2c)

    Features

    Source code(tar.gz)
    Source code(zip)
  • 0.3.10(Sep 19, 2022)

    Bug Fixes

    • "Cannot commit, no transaction is active" error in sql.js (#9234) (749809a), closes #9100
    • add missing support for primaryKeyConstraintName property in EntitySchema (cc63961)
    • malformed query when selecting deeply nested embedded entities (#9273) (83f7b88)
    • prototype pollution issue (e3aac27)
    • typescript 4.8 type issues #9331 (#9357) (a1960e1)
    • Update RelationIdLoader to use DriverUtils.getAlias (#9380) (a917d65), closes #9379

    Features

    Source code(tar.gz)
    Source code(zip)
  • 0.3.9(Aug 28, 2022)

  • 0.3.8(Aug 26, 2022)

    Bug Fixes

    Features

    Source code(tar.gz)
    Source code(zip)
  • 0.3.7(Jun 29, 2022)

    Bug Fixes

    Features

    • add for_key_share ("FOR KEY SHARE") lock mode for postgres driver (#8879) (4687be8), closes #8878
    • add nativeBinding option to better-sqlite3 driver (#9157) (bcdddc3)
    • add spanner as a db option for the init command (#9121) (e61cade)
    • allow explicitly named primary keys, foreign keys, and indices (#8900) (78df84c), closes #1355
    • Cloud Spanner support (#8730) (62518ae)
    • fix issues with generated columns and add support in other drivers (#8806) (0418ebc), closes #8761
    • implement support for relationids in entity schemas (#9129) (e24cced)
    • support TS 4.7+ node16/nodenext module mode (#9043) (862a402)
    • upgrade ioredis to v5 (#8997) (723f1e5)

    Performance Improvements

    Source code(tar.gz)
    Source code(zip)
  • 0.3.6(Apr 12, 2022)

  • 0.3.5(Apr 5, 2022)

    Bug Fixes

    • .save repository method not returning generated uuids for aurora-postgres (#8825) (ed06f4c)
    • allow hstore type to use transformers in driver postgres (#8823) (b1a0107)
    • broken shebang parameters of cli-ts-node-commonjs and cli-ts-node-esm on some linux distros (#8821) (c5dfc11), closes #8818
    • find select object api should support false values #8796 (#8807) (9ac8e9e)
    • resolve missing ConnectionOptions export in index.ts (#8850) (1693a17), closes #8837
    • save correct discriminator with STI (#8819) (9d1e246), closes #2927
    • Update DeepPartial for usage of generics with Repository class (#8817) (8ba742e)
    • fixed issue with typeorm init command (#8820)
    Source code(tar.gz)
    Source code(zip)
  • 0.3.4(Mar 26, 2022)

    Bug Fixes

    • BaseEntity.reload method regression and made findOne to throw error on missing conditions in runtime (#8801) (ee8c1ec)
    • improve DeepPartial recursion (#8732) (0494008), closes #8681
    • missing timestamp in created migrations filenames (#8802) (ceee439)
    • PoolConnection leaked by MysqlDriver (#8803) (d2cfd22)
    • remove console.log calls from SelectQueryBuilder (#8795) (54c7db4), closes #8792
    • stop crashing when redis is offline and ignoreErrors on cache options is set (#8725) (edc39d1)

    Features

    Source code(tar.gz)
    Source code(zip)
  • 0.3.3(Mar 23, 2022)

  • 0.3.2(Mar 22, 2022)

  • 0.3.1(Mar 21, 2022)

    Bug Fixes

    Features

    • new array find operators (ArrayContains, ArrayContainedBy, ArrayOverlap) (#8766) (9f1b8e3):

    BREAKING CHANGES

    • we do not call JSON.stringify() to json/jsonb column types in Postgres. Instead, we delegate value directly to underlying pg driver. This is a correct way of handling jsons.
    • array: true must be explicitly defined for array json/jsonb values
    • strings being JSON-stringified must be manually escaped
    Source code(tar.gz)
    Source code(zip)
  • 0.3.0(Mar 17, 2022)

    Changes in the version includes changes from the next branch and typeorm@next version. They were pending their migration from 2018. Finally, they are in the master branch and master version.

    Features

    • compilation target now is es2020. This requires Node.JS version 14+

    • TypeORM now properly works when installed within different node_modules contexts (often happen if TypeORM is a dependency of another library or TypeORM is heavily used in monorepo projects)

    • Connection was renamed to DataSource. Old Connection is still there, but now it's deprecated. It will be completely removed in next version. New API:

    export const dataSource = new DataSource({
        // ... options ...
    })
    
    // load entities, establish db connection, sync schema, etc.
    await dataSource.connect()
    

    Previously, you could use new Connection(), createConnection(), getConnectionManager().create(), etc. They all deprecated in favour of new syntax you can see above.

    New way gives you more flexibility and simplicity in usage.

    • new custom repositories syntax:
    export const UserRepository = myDataSource.getRepository(UserEntity).extend({
        findUsersWithPhotos() {
            return this.find({
                relations: {
                    photos: true
                }
            })
        }
    })
    

    Old ways of custom repository creation were dropped.

    • added new option on relation load strategy called relationLoadStrategy. Relation load strategy is used on entity load and determines how relations must be loaded when you query entities and their relations from the database. Used on find* methods and QueryBuilder. Value can be set to join or query.

      • join - loads relations using SQL JOIN expression
      • query - executes separate SQL queries for each relation

    Default is join, but default can be set in ConnectionOptions:

    createConnection({
        /* ... */
        relationLoadStrategy: "query"
    })
    

    Also, it can be set per-query in find* methods:

    userRepository.find({
        relations: {
            photos: true
        }
    })
    

    And QueryBuilder:

    userRepository
        .createQueryBuilder()
        .setRelationLoadStrategy("query")
    

    For queries returning big amount of data, we recommend to use query strategy, because it can be a more performant approach to query relations.

    • added new findOneBy, findOneByOrFail, findBy, countBy, findAndCountBy methods to BaseEntity, EntityManager and Repository:
    const users = await userRepository.findBy({
        name: "Michael"
    })
    

    Overall find* and count* method signatures where changed, read the "breaking changes" section for more info.

    • new select type signature in FindOptions (used in find* methods):
    userRepository.find({
        select: {
            id: true,
            firstName: true,
            lastName: true,
        }
    })
    

    Also, now it's possible to specify select columns of the loaded relations:

    userRepository.find({
        select: {
            id: true,
            firstName: true,
            lastName: true,
            photo: {
                id: true,
                filename: true,
                album: {
                    id: true,
                    name: true,
                }
            }
        }
    })
    
    • new relations type signature in FindOptions (used in find* methods):
    userRepository.find({
        relations: {
            contacts: true,
            photos: true,
        }
    })
    

    To load nested relations use a following signature:

    userRepository.find({
        relations: {
            contacts: true,
            photos: {
                album: true,
            },
        }
    })
    
    • new order type signature in FindOptions (used in find* methods):
    userRepository.find({
        order: {
            id: "ASC"
        }
    })
    

    Now supports nested order by-s:

    userRepository.find({
        order: {
            photos: {
                album: {
                    name: "ASC"
                },
            },
        }
    })
    
    • new where type signature in FindOptions (used in find* methods) now allows to build nested statements with conditional relations, for example:
    userRepository.find({
        where: {
            photos: {
                album: {
                    name: "profile"
                }
            }
        }
    })
    

    Gives you users who have photos in their "profile" album.

    • FindOperator-s can be applied for relations in where statement, for example:
    userRepository.find({
        where: {
            photos: MoreThan(10),
        }
    })
    

    Gives you users with more than 10 photos.

    • boolean can be applied for relations in where statement, for example:
    userRepository.find({
        where: {
            photos: true
        }
    })
    

    BREAKING CHANGES

    • minimal Node.JS version requirement now is 14+

    • drop ormconfig support. ormconfig still works if you use deprecated methods, however we do not recommend using it anymore, because it's support will be completely dropped in 0.4.0. If you want to have your connection options defined in a separate file, you can still do it like this:

    import ormconfig from "./ormconfig.json"
    
    const MyDataSource = new DataSource(require("./ormconfig.json"))
    

    Or even more type-safe approach with resolveJsonModule in tsconfig.json enabled:

    import ormconfig from "./ormconfig.json"
    
    const MyDataSource = new DataSource(ormconfig)
    

    But we do not recommend use this practice, because from 0.4.0 you'll only be able to specify entities / subscribers / migrations using direct references to entity classes / schemas (see "deprecations" section).

    We won't be supporting all ormconfig extensions (e.g. json, js, ts, yaml, xml, env).

    • support for previously deprecated migrations:* commands was removed. Use migration:* commands instead.

    • all commands were re-worked. Please refer to new CLI documentation.

    • cli option from BaseConnectionOptions (now BaseDataSourceOptions options) was removed (since CLI commands were re-worked).

    • now migrations are running before schema synchronization if you have both pending migrations and schema synchronization pending (it works if you have both migrationsRun and synchronize enabled in connection options).

    • aurora-data-api driver now is called aurora-mysql

    • aurora-data-api-pg driver now is called aurora-postgres

    • EntityManager.connection is now EntityManager.dataSource

    • Repository now has a constructor (breaks classes extending Repository with custom constructor)

    • @TransactionRepository, @TransactionManager, @Transaction decorators were completely removed. These decorators do the things out of the TypeORM scope.

    • Only junction table names shortened.

    MOTIVATION: We must shorten only table names generated by TypeORM. It's user responsibility to name tables short if their RDBMS limit table name length since it won't make sense to have table names as random hashes. It's really better if user specify custom table name into @Entity decorator. Also, for junction table it's possible to set a custom name using @JoinTable decorator.

    • findOne() signature without parameters was dropped. If you need a single row from the db you can use a following syntax:
    const [user] = await userRepository.find()
    

    This change was made to prevent user confusion. See this issue for details.

    • findOne(id) signature was dropped. Use following syntax instead:
    const user = await userRepository.findOneBy({
        id: id // where id is your column name
    })
    

    This change was made to provide a more type-safe approach for data querying. Due to this change you might need to refactor the way you load entities using MongoDB driver.

    • findOne, findOneOrFail, find, count, findAndCount methods now only accept FindOptions as parameter, e.g.:
    const users = await userRepository.find({
        where: { /* conditions */ },
        relations: { /* relations */ }
    })
    

    To supply where conditions directly without FindOptions new methods were added: findOneBy, findOneByOrFail, findBy, countBy, findAndCountBy. Example:

    const users = await userRepository.findBy({
        name: "Michael"
    })
    

    This change was required to simply current find* and count* methods typings, improve type safety and prevent user confusion.

    • findByIds was deprecated, use findBy method instead in conjunction with In operator, for example:
    userRepository.findBy({
        id: In([1, 2, 3])
    })
    

    This change was made to provide a more type-safe approach for data querying.

    • findOne and QueryBuilder.getOne() now return null instead of undefined in the case if it didn't find anything in the database. Logically it makes more sense to return null.

    • findOne now limits returning rows to 1 at database level.

    NOTE: FOR UPDATE locking does not work with findOne in Oracle since FOR UPDATE cannot be used with FETCH NEXT in a single query.

    • where in FindOptions (e.g. find({ where: { ... })) is more sensitive to input criteria now.

    • FindConditions (where in FindOptions) was renamed to FindOptionsWhere.

    • null as value in where used in find* methods is not supported anymore. Now you must explicitly use IsNull() operator.

    Before:

    userRepository.find({
        where: {
            photo: null
        }
    })
    

    After:

    userRepository.find({
        where: {
            photo: IsNull()
        }
    })
    

    This change was made to make it more transparent on how to add "IS NULL" statement to final SQL, because before it bring too much confusion for ORM users.

    • if you had entity properties of a non-primitive type (except Buffer) defined as columns, then you won't be able to use it in find*'s where. Example:

    Before for the @Column(/*...*/) membership: MembershipKind you could have a query like:

    userRepository.find({
        membership: new MembershipKind("premium")
    })
    

    now, you need to wrap this value into Equal operator:

    userRepository.find({
        membership: Equal(new MembershipKind("premium"))
    })
    

    This change is due to type-safety improvement new where signature brings.

    • order in FindOptions (used in find* methods) doesn't support ordering by relations anymore. Define relation columns, and order by them instead.

    • where in FindOptions (used in find* methods) previously supported ObjectLiteral and string types. Now both signatures were removed. ObjectLiteral was removed because it seriously breaks the type safety, and string doesn't make sense in the context of FindOptions. Use QueryBuilder instead.

    • MongoRepository and MongoEntityManager now use new types called MongoFindManyOptions and MongoFindOneOptions for their find* methods.

    • primary relation (e.g. @ManyToOne(() => User, { primary: true }) user: User) support is removed. You still have an ability to use foreign keys as your primary keys, however now you must explicitly define a column marked as primary.

    Example, before:

    @ManyToOne(() => User, { primary: true })
    user: User
    

    Now:

    @PrimaryColumn()
    userId: number
    
    @ManyToOne(() => User)
    user: User
    

    Primary column name must match the relation name + join column name on related entity. If related entity has multiple primary keys, and you want to point to multiple primary keys, you can define multiple primary columns the same way:

    @PrimaryColumn()
    userFirstName: string
    
    @PrimaryColumn()
    userLastName: string
    
    @ManyToOne(() => User)
    user: User
    

    This change was required to simplify ORM internals and introduce new features.

    • prefix relation id columns contained in embedded entities (#7432)

    • find by Date object in sqlite driver (#7538)

    • issue with non-reliable new Date(ISOString) parsing (#7796)

    DEPRECATIONS

    • all CLI commands do not support ormconfig anymore. You must specify a file with data source instance instead.

    • entities, migrations, subscribers options inside DataSourceOptions accepting string directories support is deprecated. You'll be only able to pass entity references in the future versions.

    • all container-related features (UseContainerOptions, ContainedType, ContainerInterface, defaultContainer, useContainer, getFromContainer) are deprecated.

    • EntityManager's getCustomRepository used within transactions is deprecated. Use withRepository method instead.

    • Connection.isConnected is deprecated. Use .isInitialized instead.

    • select in FindOptions (used in find* methods) used as an array of property names is deprecated. Now you should use a new object-literal notation. Example:

    Deprecated way of loading entity relations:

    userRepository.find({
        select: ["id", "firstName", "lastName"]
    })
    

    New way of loading entity relations:

    userRepository.find({
        select: {
            id: true,
            firstName: true,
            lastName: true,
        }
    })
    

    This change is due to type-safety improvement new select signature brings.

    • relations in FindOptions (used in find* methods) used as an array of relation names is deprecated. Now you should use a new object-literal notation. Example:

    Deprecated way of loading entity relations:

    userRepository.find({
        relations: ["contacts", "photos", "photos.album"]
    })
    

    New way of loading entity relations:

    userRepository.find({
        relations: {
            contacts: true,
            photos: {
                album: true
            }
        }
    })
    

    This change is due to type-safety improvement new relations signature brings.

    • join in FindOptions (used in find* methods) is deprecated. Use QueryBuilder to build queries containing manual joins.

    • Connection, ConnectionOptions are deprecated, new names to use are: DataSource and DataSourceOptions. To create the same connection you had before use a new syntax: new DataSource({ /*...*/ }).

    • createConnection(), createConnections() are deprecated, since Connection is called DataSource now, to create a connection and connect to the database simply do:

    const myDataSource = new DataSource({ /*...*/ })
    await myDataSource.connect()
    
    • getConnection() is deprecated. To have a globally accessible connection, simply export your data source and use it in places you need it:
    export const myDataSource = new DataSource({ /*...*/ })
    // now you can use myDataSource anywhere in your application
    
    • getManager(), getMongoManager(), getSqljsManager(), getRepository(), getTreeRepository(), getMongoRepository(), createQueryBuilder() are all deprecated now. Use globally accessible data source instead:
    export const myDataSource = new DataSource({ /*...*/ })
    export const Manager = myDataSource.manager
    export const UserRepository = myDataSource.getRepository(UserEntity)
    export const PhotoRepository = myDataSource.getRepository(PhotoEntity)
    // ...
    
    • getConnectionManager() and ConnectionManager itself are deprecated - now Connection is called DataSource, and each data source can be defined in exported variable. If you want to have a collection of data sources, just define them in a variable, simply as:
    const dataSource1 = new DataSource({ /*...*/ })
    const dataSource2 = new DataSource({ /*...*/ })
    const dataSource3 = new DataSource({ /*...*/ })
    
    export const MyDataSources = {
        dataSource1,
        dataSource2,
        dataSource3,
    }
    
    • getConnectionOptions() is deprecated - in next version we are going to implement different mechanism of connection options loading

    • AbstractRepository is deprecated. Use new way of custom repositories creation.

    • Connection.name and BaseConnectionOptions.name are deprecated. Connections don't need names anymore since we are going to drop all related methods relying on this property.

    • all deprecated signatures will be removed in 0.4.0

    EXPERIMENTAL FEATURES NOT PORTED FROM NEXT BRANCH

    • observers - we will consider returning them back with new API in future versions
    • alternative find operators - using $any, $in, $like and other operators in where condition.
    Source code(tar.gz)
    Source code(zip)
  • 0.2.45(Mar 4, 2022)

    0.2.45 (2022-03-04)

    Bug Fixes

    Features

    Source code(tar.gz)
    Source code(zip)
  • 0.2.44(Feb 23, 2022)

    0.2.44 (2022-02-23)

    Bug Fixes

    • alter relation loader to use transforms when present (#8691) (2c2fb29), closes #8690
    • cannot read properties of undefined (reading 'joinEagerRelations') (136015b)
    • expo driver doesn't work properly because of new beforeMigration() afterMigration() callbacks (#8683) (5a71803)
    • ng webpack default import (#8688) (2d3374b), closes #8674
    • support imports of absolute paths of ESM files on Windows (#8669) (12cbfcd), closes #8651

    Features

    • add option to upsert to skip update if the row already exists and no values would be changed (#8679) (8744395)
    • allow {delete,insert}().returning() on MariaDB (#8673) (7facbab), closes #7235 #7235
    • Implement deferrable foreign keys for SAP HANA (#6104) (1f54c70)
    Source code(tar.gz)
    Source code(zip)
  • 0.2.43(Feb 17, 2022)

  • 0.2.42(Feb 16, 2022)

    0.2.42 (2022-02-16)

    Bug Fixes

    • proper column comment mapping from database to metadata in aurora-data-api (baa5880)
    • add referencedSchema to PostgresQueryRunner (#8566) (c490319)
    • adding/removing @Generated() will now generate a migration to add/remove the DEFAULT value (#8274) (4208393), closes #5898
    • adds entity-schema support for createForeignKeyConstraints (#8606) (f224f24), closes #8489
    • allow special keyword as column name for simple-enum type on sqlite (#8645) (93bf96e)
    • correctly handle multiple-row insert for SAP HANA driver (#7957) (8f2ae71)
    • disable SQLite FK checks in synchronize / migrations (#7922) (f24822e)
    • find descendants of a non-existing tree parent (#8557) (cbb61eb), closes #8556
    • For MS SQL Server use lowercase "sys"."columns" reference. (#8400) (#8401) (e8a0f92)
    • improve DeepPartial type (#8187) (b93416d)
    • Lock peer dependencies versions (#8597) (600bd4e)
    • make EntityMetadataValidator comply with entitySkipConstructor, cover with test (#8445) (3d6c5da), closes #8444
    • materialized path being computed as "undefined1." (#8526) (09f54e0)
    • MongoConnectionOptions sslCA type mismatch (#8628) (02400da)
    • mongodb repository.find filters soft deleted rows (#8581) (f7c1f7d), closes #7113
    • mongodb@4 compatibility support (#8412) (531013b)
    • must invoke key pragma before any other interaction if SEE setted (#8478) (546b3ed), closes #8475
    • nested eager relations in a lazy-loaded entity are not loaded (#8564) (1cfd7b9)
    • QueryFailedError when tree entity with JoinColumn (#8443) (#8447) (a11c50d)
    • relation id and afterAll hook performance fixes (#8169) (31f0b55)
    • replaced custom uuid generator with uuid library (#8642) (8898a71)
    • single table inheritance returns the same discriminator value error for unrelated tables where their parents extend from the same entity (#8525) (6523fcc), closes #8522
    • updating with only update: false columns shouldn't trigger @UpdateDateColumn column updation (2834729), closes #8394 #8394 #8394
    • upsert should find unique index created by one-to-one relation (#8618) (c8c00ba)

    Features

    Reverts

    • migration:show command must exist with zero status code (Fixes #7349) (#8185) (e0adeee)

    BREAKING CHANGES

    • update listeners and subscriber no longer triggered by soft-remove and recover
    Source code(tar.gz)
    Source code(zip)
  • 0.2.41(Nov 18, 2021)

    Bug Fixes

    • add retryWrites to MongoConnectionOptions (#8354) (c895680), closes #7869
    • create typeorm_metadata table when running migrations (#4956) (b2c8168)
    • db caching won't work with replication enabled (#7694) (2d0abe7), closes #5919
    • incorrect composite UNIQUE constraints detection (#8364) (29cb891), closes #8158
    • Postgres enum generates unnecessary queries on schema sync (#8268) (98d5f39)
    • resolve issue delete column null on after update event subscriber (#8318) (8a5e671), closes #6327

    Features

    Source code(tar.gz)
    Source code(zip)
  • 0.2.40(Nov 11, 2021)

    Bug Fixes

    • BaseEntity finder methods to properly type-check lazy relations conditions (#5710) (0665ff5)

    Features

    • add depth limiter optional parameter when loading nested trees using TreeRepository's findTrees() and findDescendantsTree() (#7926) (0c44629), closes #3909
    • add upsert methods for the drivers that support onUpdate (#8104) (3f98197), closes #2363
    • Postgres IDENTITY Column support (#7741) (969af95)

    Reverts

    Source code(tar.gz)
    Source code(zip)
  • 0.2.39(Nov 9, 2021)

    Bug Fixes

    • attach FOR NO KEY UPDATE lock to query if required (#8008) (9692930), closes #7717
    • cli should accept absolute paths for --config (4ad3a61)
    • create a different cacheId if present for count query in getManyAndCount (#8283) (9f14e48), closes #4277
    • defaults type cast filtering in Cockroachdb (#8144) (28c183e), closes #7110 #7110
    • do not generate migration for unchanged enum column (#8161) (#8164) (4638dea)
    • NativescriptQueryRunner's query method fails when targeting es2017 (#8182) (8615733)
    • OneToManySubjectBuilder bug with multiple primary keys (#8221) (6558295)
    • ordering by joined columns for PostgreSQL (#3736) (#8118) (1649882)
    • support DeleteResult in SQLiteDriver (#8237) (b678807)

    Features

    • add typeorm command wrapper to package.json in project template (#8081) (19d4a91)
    • add dependency configuraiton for views #8240 (#8261) (2c861af)
    • add relation options to all tree queries (#8080) (e4d4636), closes #8076
    • add the ability to pass the driver into all database types (#8259) (2133ffe)
    • more informative logging in case of migration failure (#8307) (dc6f1c9)
    • support using custom index with SelectQueryBuilder in MySQL (#7755) (f79ae58)

    Reverts

    • Revert "fix: STI types on children in joins (#3160)" (#8309) (0adad88), closes #3160 #8309
    Source code(tar.gz)
    Source code(zip)
  • 0.2.38(Oct 2, 2021)

  • 0.2.37(Aug 13, 2021)

    Bug Fixes

    • allow periods in parameter identifiers (#8022) (4201938)
    • ConnectionManager connections property should include list of Connections (#8004) (2344db6)
    • entity value for date columns that are related (#8027) (5a3767f)
    • handle brackets when only one condition is passed (#8048) (ab39066)
    • handle enums with multiple apostrophes in MySQL (#8013) (37c40a6), closes #8011
    • include all drivers in driverfactory error message (#8061) (fbd1ef7)
    • resolve not returning soft deleted relations with withDeleted find option (#8017) (65cbcc7)
    • SAP HANA inserts used incorrect value for returning query (#8072) (36398db)
    • some drivers set the wrong database name when defined from url (#8058) (a3a3284)
    • throw error when not connected in drivers (#7995) (cd71f62)

    Features

    Source code(tar.gz)
    Source code(zip)
  • 0.2.36(Jul 31, 2021)

  • 0.2.35(Jul 29, 2021)

    Bug Fixes

    • entity to be Partial<Entity> | undefined in UpdateEvent (#7783) (f033045)
    • actually return a working ReadStream from SQL Server query runner (#7893) (e80985f)
    • added version check before dropping materialized views to keep backward compatibility (#7716) (29f1f86)
    • allow for string id in mongo.findByIds call (#7838) (4b45ae1)
    • better support of relation-based properties in where clauses (#7805) (3221c50)
    • Buffer in primary columns causes bugs with relations (#7952) (37e08a7), closes #4060
    • capacitor does not correctly set journal mode (#7873) (5f20eb7)
    • Capacitor driver PRAGMA requests failing on Android (#7728) (9620a26)
    • condition is optional in SelectQueryBuilder joins (#7888) (2deaa0e)
    • correctly handle mongo replica set driver option (#7908) (9212df4)
    • correctly load yml in ConnectionOptionsYmlReader (#7743) (57f9254)
    • craft oracle connectString as a descriptor with SID (#7878) (b05d093)
    • delete operation in MongoDB impact all matched documents (#7811) (0fbae53), closes #7809
    • Do not add NULL/NOT NULL for stored columns (#7708) (3c33e9f), closes #7698
    • do OBJECT_ID lookup for column constraint instead of name in mssql (#7916) (fa8c1b0)
    • drop pool.autostart from mssql options because it's unused (#7877) (0d21a4d)
    • drop SAP statement after prepare per Hana client docs (#7748) (8ca05b1)
    • eager relation respects children relations (#5685) (e7e887a)
    • enable returning additional columns with MSSQL (#7864) (e1db48d)
    • entity object undefined in afterUpdate subscriber (#7724) (d25304d)
    • find operation in MongoDB do not include nullable values from documents (#7820) (98c13cf), closes #7760
    • fix table loading when schemas are used (3a106a3)
    • foreign keys in SAP were loading from the wrong table (#7914) (4777a79)
    • handle postgres default when tableColumn.default is not string (#7816) (0463855)
    • handle snake case of ABcD which should become a_bc_d (#7883) (eb680f9)
    • improve query for MSSQL to fetch foreign keys and tables (#7935) (f6af01a)
    • make OracleQueryRunner createDatabase if-not-exists not fail (f5a80ef)
    • only pass data from SaveOptions during that query (#7886) (1de2e13)
    • oracle cannot support DB in table identifiers (#7954) (8c60d91)
    • pass table to namingstrategy when we can instead of table name (#7925) (140002d)
    • prevent modification of the FindOptions.relations (#7887) (a2fcad6)
    • prevent reuse of broken connections in postgres pool (#7792) (5cf368a)
    • prevent transactions in the Cordova driver (#7771) (fc4133c)
    • properly escape oracle table paths (#7917) (7e8687c)
    • regression when making join conditions undefined-able (#7892) (b0c1cc6)
    • restored buildColumnAlias for backward compatibility (#7706) (36ceefa)
    • return correct DeleteResult and UpdateResult for mongo (#7884) (7a646a2)
    • support fully qualified schema in createSchema (#7934) (94edd12)
    • support table names between schemas in oracle (#7951) (aa45b93)
    • typing so SelectQueryBuilder.getRawOne may return undefined (#7863) (36e5a0c), closes #7449
    • typo prevented us from pulling the schema correctly in some cases (c7f2db8)
    • update operation in MongoDB impact all matched documents (#7803) (052014c), closes #7788
    • use correct query for cross-database mssql identity check (#7911) (7869fb1)
    • use fully qualified and escaped table names for oracle (#7857) (2b90725), closes #7779
    • use ObjectLiteral in UpdateEvent rather than Entity (#7910) (78fbc14)
    • use only table name in constraint naming strategy (5dc777f)

    Features

    Source code(tar.gz)
    Source code(zip)
Next-generation ORM for Node.js & TypeScript | PostgreSQL, MySQL, MariaDB, SQL Server & SQLite

Prisma Quickstart • Website • Docs • Examples • Blog • Slack • Twitter • Prisma 1 What is Prisma? Prisma is a next-generation ORM that consists of the

Prisma 28k Jan 2, 2023
Database manager for MySQL, PostgreSQL, SQL Server, MongoDB, SQLite and others. Runs under Windows, Linux, Mac or as web application

Database manager for MySQL, PostgreSQL, SQL Server, MongoDB, SQLite and others. Runs under Windows, Linux, Mac or as web application

DbGate 2k Dec 30, 2022
A Node.js ORM for MySQL, SQLite, PostgreSQL, MongoDB, GitHub and serverless service like Deta, InspireCloud, CloudBase, LeanCloud.

Dittorm A Node.js ORM for MySQL, SQLite, PostgreSQL, MongoDB, GitHub and serverless service like Deta, InspireCloud, CloudBase, LeanCloud. Installatio

Waline 21 Dec 25, 2022
Azure Data Studio is a data management tool that enables you to work with SQL Server, Azure SQL DB and SQL DW from Windows, macOS and Linux.

Azure Data Studio is a data management tool that enables working with SQL Server, Azure SQL DB and SQL DW from Windows, macOS and Linux.

Microsoft 7k Dec 31, 2022
An adapter-based ORM for Node.js with support for mysql, mongo, postgres, mssql (SQL Server), and more

Waterline is a next-generation storage and retrieval engine, and the default ORM used in the Sails framework. It provides a uniform API for accessing

Balderdash 5.4k Jan 4, 2023
A simple Node.js ORM for PostgreSQL, MySQL and SQLite3 built on top of Knex.js

bookshelf.js Bookshelf is a JavaScript ORM for Node.js, built on the Knex SQL query builder. It features both Promise-based and traditional callback i

Bookshelf.js 6.3k Jan 2, 2023
Explore, create and deploy your SQLite databases right from your browser. Quick and easy, no installation required.

SQLighter (under development, alpha code) SQLighter is a database explorer born for SQLite that helps you design and deploy your application database

sqlighter 11 Sep 20, 2022
TypeScript clients for databases that prevent SQL Injection

Safe From HTML Injection Using tagged template literals for queries, e.g. db.query(sql`SELECT * FROM users WHERE id=${userID}`); makes it virtually im

Forbes Lindesay 478 Dec 21, 2022
This is a demo sample of linking NODEJS via ORM and MYSQL

Demons(Demo of Nodejs with SQL) This is a demo sample of linking NODEJS with ORM and MYSQL Connecting Node to SQL is a hard task and not much help is

Shivam Sourav Jha 3 Apr 14, 2022
A simple url shorter API built with nodejs running on Kubernetes in Google Cloud, using PostgreSQL for storage and cloud sql proxy.

Simple URL Shorter - Google Cloud - Kubernetes A simple url shorter API built with nodejs running on Kubernetes in Google Cloud, using PostgreSQL for

null 3 Nov 25, 2021
Lovefield is a relational database for web apps. Written in JavaScript, works cross-browser. Provides SQL-like APIs that are fast, safe, and easy to use.

Lovefield Lovefield is a relational database written in pure JavaScript. It provides SQL-like syntax and works cross-browser (currently supporting Chr

Google 6.8k Jan 3, 2023
Validate and auto-generate TypeScript types from raw SQL queries in PostgreSQL.

SafeQL Write SQL Queries With Confidence • Get started Install I would first recommend follow the instructions in the documentation. npm install --sav

null 747 Dec 28, 2022
just a graphql example created by typescript + fastify + mikro-orm(postgresql) + mercurius(graphql adaptor) + type-graphql

fastify-mikro-orm-mercurius-graphql-example A MikroORM boilerplate for GraphQL made with Fastify, Mercurius, Typescript using TypeGraphQL ?? Packages

Vigen 10 Aug 28, 2022
Ecommerce-backend-nestjs - Ecommerce app with Nestjs + Prisma ORM + GraphQL + SQLite

ECOMMERCE BACKEND NESTJS APP Nestjs + Prisma ORM + GraphQL + SQLite USER Create Account Login Product Create Product Get Products Get Product Search P

Rui Paulo Calei 5 Apr 6, 2022
An easy-to-use multi SQL dialect ORM tool for Node.js

Sequelize Sequelize is a promise-based Node.js ORM tool for Postgres, MySQL, MariaDB, SQLite and Microsoft SQL Server. It features solid transaction s

Sequelize 27.3k Jan 4, 2023
An SQL-friendly ORM for Node.js

Objection.js Objection.js is an ORM for Node.js that aims to stay out of your way and make it as easy as possible to use the full power of SQL and the

Vincit 6.9k Jan 5, 2023
Connect to private Google Cloud SQL instance through Cloud SQL Auth Proxy running in Kubernetes.

⛅ google-cloud-sql A CLI app which establishes a connection to a private Google Cloud SQL instance and port-forwards it to a local machine. Connection

Dinko Osrecki 10 Oct 16, 2022
A typesafe database ORM that exposes the full power of handwritten sql statements to the developer.

TORM A typesafe database ORM that exposes the full power of handwritten sql statements to the developer. import { torm, z } from 'https://deno.land/x/

Andrew Kaiser 15 Dec 22, 2022