feat: support MAX_EXECUTION_TIME for MySQL driver. (#7638)

This commit is contained in:
Hong Truong 2021-05-15 19:33:34 +10:00 committed by GitHub
parent dba327d426
commit 0564c348b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 48 additions and 1 deletions

View File

@ -22,6 +22,7 @@
* [Streaming result data](#streaming-result-data)
* [Using pagination](#using-pagination)
* [Set locking](#set-locking)
* [Max execution time](#max-execution-time)
* [Partial selection](#partial-selection)
* [Using subqueries](#using-subqueries)
* [Hidden Columns](#hidden-columns)
@ -914,6 +915,17 @@ const users = await getRepository(User)
Optimistic locking works in conjunction with both `@Version` and `@UpdatedDate` decorators.
## Max execution time
We can drop slow query to avoid crashing the server. Only MySQL driver is supported at the moment:
```typescript
const users = await getRepository(User)
.createQueryBuilder("user")
.maxExecutionTime(1000) // milliseconds.
.getMany();
```
## Partial selection
If you want to select only some entity properties, you can use the following syntax:

View File

@ -46,6 +46,11 @@ export class QueryExpressionMap {
*/
selects: SelectQuery[] = [];
/**
* Max execution time in millisecond.
*/
maxExecutionTime: number = 0;
/**
* Whether SELECT is DISTINCT.
*/
@ -399,6 +404,7 @@ export class QueryExpressionMap {
const map = new QueryExpressionMap(this.connection);
map.queryType = this.queryType;
map.selects = this.selects.map(select => select);
map.maxExecutionTime = this.maxExecutionTime;
map.selectDistinct = this.selectDistinct;
map.selectDistinctOn = this.selectDistinctOn;
this.aliases.forEach(alias => map.aliases.push(new Alias(alias)));

View File

@ -163,6 +163,15 @@ export class SelectQueryBuilder<Entity> extends QueryBuilder<Entity> implements
return this;
}
/**
* Set max execution time.
* @param milliseconds
*/
maxExecutionTime(milliseconds: number): this {
this.expressionMap.maxExecutionTime = milliseconds;
return this;
}
/**
* Sets whether the selection is DISTINCT.
*/
@ -1448,10 +1457,17 @@ export class SelectQueryBuilder<Entity> extends QueryBuilder<Entity> implements
* Creates select | select distinct part of SQL query.
*/
protected createSelectDistinctExpression(): string {
const {selectDistinct, selectDistinctOn} = this.expressionMap;
const {selectDistinct, selectDistinctOn, maxExecutionTime} = this.expressionMap;
const {driver} = this.connection;
let select = "SELECT ";
if (maxExecutionTime > 0) {
if (driver instanceof MysqlDriver) {
select += ` /*+ MAX_EXECUTION_TIME(${ this.expressionMap.maxExecutionTime }) */`;
}
}
if (driver instanceof PostgresDriver && selectDistinctOn.length > 0) {
const selectDistinctOnMap = selectDistinctOn.map(
(on) => this.replacePropertyNames(on)

View File

@ -4,6 +4,7 @@ import {Connection} from "../../../../src/connection/Connection";
import {Post} from "./entity/Post";
import {expect} from "chai";
import {EntityNotFoundError} from "../../../../src/error/EntityNotFoundError";
import { MysqlDriver } from '../../../../src/driver/mysql/MysqlDriver';
describe("query builder > select", () => {
@ -153,4 +154,16 @@ describe("query builder > select", () => {
.getOneOrFail()
).to.be.rejectedWith(EntityNotFoundError);
})));
it("Support max execution time", async () => Promise.all(
connections
.filter(connection => connection.driver instanceof MysqlDriver)
.map(async connection => {
const sql = connection
.createQueryBuilder(Post, "post")
.maxExecutionTime(1000)
.getSql();
expect(sql).contains("SELECT /*+ MAX_EXECUTION_TIME(1000) */");
})
));
});