diff --git a/docs/find-options.md b/docs/find-options.md index fc2363db3..138a7a668 100644 --- a/docs/find-options.md +++ b/docs/find-options.md @@ -120,7 +120,7 @@ userRepository.find({ ``` or ```ts -{ mode: "pessimistic_read"|"pessimistic_write" } +{ mode: "pessimistic_read"|"pessimistic_write"|"dirty_read" } ``` for example: diff --git a/docs/select-query-builder.md b/docs/select-query-builder.md index 87775824d..78cac5d30 100644 --- a/docs/select-query-builder.md +++ b/docs/select-query-builder.md @@ -825,6 +825,14 @@ const users = await getRepository(User) .getMany(); ``` +To use dirty read locking use the following method: + +```typescript +const users = await getRepository(User) + .createQueryBuilder("user") + .setLock("dirty_read") + .getMany(); + To use optimistic locking use the following method: ```typescript diff --git a/src/query-builder/QueryExpressionMap.ts b/src/query-builder/QueryExpressionMap.ts index 501e13867..dadb92f72 100644 --- a/src/query-builder/QueryExpressionMap.ts +++ b/src/query-builder/QueryExpressionMap.ts @@ -140,7 +140,7 @@ export class QueryExpressionMap { /** * Locking mode. */ - lockMode?: "optimistic"|"pessimistic_read"|"pessimistic_write"; + lockMode?: "optimistic"|"pessimistic_read"|"pessimistic_write"|"dirty_read"; /** * Current version of the entity, used for locking. diff --git a/src/query-builder/SelectQueryBuilder.ts b/src/query-builder/SelectQueryBuilder.ts index c602f350a..135e60dbd 100644 --- a/src/query-builder/SelectQueryBuilder.ts +++ b/src/query-builder/SelectQueryBuilder.ts @@ -949,12 +949,12 @@ export class SelectQueryBuilder extends QueryBuilder implements /** * Sets locking mode. */ - setLock(lockMode: "pessimistic_read"|"pessimistic_write"): this; + setLock(lockMode: "pessimistic_read"|"pessimistic_write"|"dirty_read"): this; /** * Sets locking mode. */ - setLock(lockMode: "optimistic"|"pessimistic_read"|"pessimistic_write", lockVersion?: number|Date): this { + setLock(lockMode: "optimistic"|"pessimistic_read"|"pessimistic_write"|"dirty_read", lockVersion?: number|Date): this { this.expressionMap.lockMode = lockMode; this.expressionMap.lockVersion = lockVersion; return this; @@ -1385,6 +1385,9 @@ export class SelectQueryBuilder extends QueryBuilder implements case "pessimistic_write": lock = " WITH (UPDLOCK, ROWLOCK)"; break; + case "dirty_read": + lock = " WITH (NOLOCK)"; + break; } } @@ -1616,6 +1619,16 @@ export class SelectQueryBuilder extends QueryBuilder implements } else if (driver instanceof SqlServerDriver) { return ""; + } else { + throw new LockNotSupportedOnGivenDriverError(); + } + case "dirty_read": + if (driver instanceof SqlServerDriver) { + return " WITH (NOLOCK)"; + + } else if (driver instanceof MysqlDriver || driver instanceof PostgresDriver || driver instanceof OracleDriver) { + return ""; + } else { throw new LockNotSupportedOnGivenDriverError(); } diff --git a/test/functional/query-builder/locking/query-builder-locking.ts b/test/functional/query-builder/locking/query-builder-locking.ts index c60027cb6..aa43fc140 100644 --- a/test/functional/query-builder/locking/query-builder-locking.ts +++ b/test/functional/query-builder/locking/query-builder-locking.ts @@ -99,6 +99,21 @@ describe("query builder > locking", () => { } }))); + it("should attach dirty read lock statement on query if locking enabled", () => Promise.all(connections.map(async connection => { + if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof CockroachDriver) + return; + + const sql = connection.createQueryBuilder(PostWithVersion, "post") + .setLock("dirty_read") + .where("post.id = :id", { id: 1 }) + .getSql(); + + if (connection.driver instanceof SqlServerDriver) { + expect(sql.indexOf("WITH (NOLOCK)") !== -1).to.be.true; + + } + }))); + it("should not attach pessimistic write lock statement on query if locking is not used", () => Promise.all(connections.map(async connection => { if (connection.driver instanceof AbstractSqliteDriver) return; @@ -129,6 +144,20 @@ describe("query builder > locking", () => { }))); + it("should attach pessimistic read lock statement on query if locking enabled", () => Promise.all(connections.map(async connection => { + if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof CockroachDriver) + return; + + const sql = connection.createQueryBuilder(PostWithVersion, "post") + .setLock("dirty_read") + .where("post.id = :id", { id: 1 }) + .getSql(); + + if (connection.driver instanceof SqlServerDriver) { + expect(sql.indexOf("WITH (NOLOCK)") !== -1).to.be.true; + } + }))); + it("should throw error if optimistic lock used with getMany method", () => Promise.all(connections.map(async connection => { return connection.createQueryBuilder(PostWithVersion, "post")