Skip to content

Commit

Permalink
feat: Add SelectQueryBuilder.getOneOrFail() (#6885)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
imnotjames committed Oct 16, 2020
1 parent 9635080 commit 920e781
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 0 deletions.
10 changes: 10 additions & 0 deletions docs/select-query-builder.md
Expand Up @@ -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`:

Expand Down
14 changes: 14 additions & 0 deletions src/query-builder/SelectQueryBuilder.ts
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
*/
Expand Down
43 changes: 43 additions & 0 deletions test/functional/query-builder/select/query-builder-select.ts
Expand Up @@ -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", () => {

Expand Down Expand Up @@ -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);
})));
});

0 comments on commit 920e781

Please sign in to comment.