feat: Add SelectQueryBuilder.getOneOrFail() (#6885)

This adds a `getOneOrFail` which which is to `getOne` as
`findOneOrFail` is to `findOne` - it never returns `undefined`,
it will instead throw an `EntityNotFoundError`

closes #6246
This commit is contained in:
James Ward 2020-10-15 22:54:57 -04:00 committed by GitHub
parent 96350805fb
commit 920e7812cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 67 additions and 0 deletions

View File

@ -174,6 +174,16 @@ const timber = await getRepository(User)
.getOne();
```
`getOneOrFail` will get a single result from the database, but if
no result exists it will throw an `EntityNotFoundError`:
```typescript
const timber = await getRepository(User)
.createQueryBuilder("user")
.where("user.id = :id OR user.name = :name", { id: 1, name: "Timber" })
.getOneOrFail();
```
To get multiple results from the database,
for example, to get all users from the database, use `getMany`:

View File

@ -37,6 +37,7 @@ import {ObjectUtils} from "../util/ObjectUtils";
import {DriverUtils} from "../driver/DriverUtils";
import {AuroraDataApiDriver} from "../driver/aurora-data-api/AuroraDataApiDriver";
import {CockroachDriver} from "../driver/cockroachdb/CockroachDriver";
import {EntityNotFoundError} from "../error/EntityNotFoundError";
/**
* Allows to build complex sql queries in a fashion way and execute those queries.
@ -1105,6 +1106,19 @@ export class SelectQueryBuilder<Entity> extends QueryBuilder<Entity> implements
return result;
}
/**
* Gets the first entity returned by execution of generated query builder sql or rejects the returned promise on error.
*/
async getOneOrFail(): Promise<Entity> {
const entity = await this.getOne();
if (!entity) {
throw new EntityNotFoundError(this.expressionMap.mainAlias!.target, this);
}
return entity;
}
/**
* Gets entities returned by execution of generated query builder sql.
*/

View File

@ -3,6 +3,7 @@ import {closeTestingConnections, createTestingConnections, reloadTestingDatabase
import {Connection} from "../../../../src/connection/Connection";
import {Post} from "./entity/Post";
import {expect} from "chai";
import {EntityNotFoundError} from "../../../../src/error/EntityNotFoundError";
describe("query builder > select", () => {
@ -110,4 +111,46 @@ describe("query builder > select", () => {
expect(sql).to.equal("SELECT post.name FROM post post");
})));
it("should return a single entity for getOne when found", () => Promise.all(connections.map(async connection => {
await connection.getRepository(Post).save({ id: 1, title: "Hello", description: 'World', rating: 0 });
const entity = await connection.createQueryBuilder(Post, "post")
.where("post.id = :id", { id: 1 })
.getOne();
expect(entity).not.to.be.undefined;
expect(entity!.id).to.equal(1);
expect(entity!.title).to.equal("Hello");
})));
it("should return undefined for getOne when not found", () => Promise.all(connections.map(async connection => {
await connection.getRepository(Post).save({ id: 1, title: "Hello", description: 'World', rating: 0 });
const entity = await connection.createQueryBuilder(Post, "post")
.where("post.id = :id", { id: 2 })
.getOne();
expect(entity).to.be.undefined;
})));
it("should return a single entity for getOneOrFail when found", () => Promise.all(connections.map(async connection => {
await connection.getRepository(Post).save({ id: 1, title: "Hello", description: 'World', rating: 0 });
const entity = await connection.createQueryBuilder(Post, "post")
.where("post.id = :id", { id: 1 })
.getOneOrFail();
expect(entity.id).to.equal(1);
expect(entity.title).to.equal("Hello");
})));
it("should throw an Error for getOneOrFail when not found", () => Promise.all(connections.map(async connection => {
await connection.getRepository(Post).save({ id: 1, title: "Hello", description: 'World', rating: 0 });
await expect(
connection.createQueryBuilder(Post, "post")
.where("post.id = :id", { id: 2 })
.getOneOrFail()
).to.be.rejectedWith(EntityNotFoundError);
})));
});