Skip to content

Commit

Permalink
feat: add support for ON CONFLICT for cockroach (#4518)
Browse files Browse the repository at this point in the history
Closes: #4513
  • Loading branch information
HNicolas authored and pleerock committed Sep 5, 2019
1 parent 19e2179 commit db8074a
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 3 deletions.
6 changes: 3 additions & 3 deletions src/query-builder/InsertQueryBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ export class InsertQueryBuilder<Entity> extends QueryBuilder<Entity> {
}

/**
* Adds additional ON CONFLICT statement supported in postgres.
* Adds additional ON CONFLICT statement supported in postgres and cockroach.
*/
onConflict(statement: string): this {
this.expressionMap.onConflict = statement;
Expand Down Expand Up @@ -249,7 +249,7 @@ export class InsertQueryBuilder<Entity> extends QueryBuilder<Entity> {
if (statement && statement.overwrite instanceof Array) {
if (this.connection.driver instanceof MysqlDriver) {
this.expressionMap.onUpdate.overwrite = statement.overwrite.map(column => `${column} = VALUES(${column})`).join(", ");
} else if (this.connection.driver instanceof PostgresDriver || this.connection.driver instanceof AbstractSqliteDriver) {
} else if (this.connection.driver instanceof PostgresDriver || this.connection.driver instanceof AbstractSqliteDriver || this.connection.driver instanceof CockroachDriver) {
this.expressionMap.onUpdate.overwrite = statement.overwrite.map(column => `${column} = EXCLUDED.${column}`).join(", ");
}
}
Expand Down Expand Up @@ -300,7 +300,7 @@ export class InsertQueryBuilder<Entity> extends QueryBuilder<Entity> {
query += ` DEFAULT VALUES`;
}
}
if (this.connection.driver instanceof PostgresDriver || this.connection.driver instanceof AbstractSqliteDriver) {
if (this.connection.driver instanceof PostgresDriver || this.connection.driver instanceof AbstractSqliteDriver || this.connection.driver instanceof CockroachDriver) {
query += `${this.expressionMap.onIgnore ? " ON CONFLICT DO NOTHING " : ""}`;
query += `${this.expressionMap.onConflict ? " ON CONFLICT " + this.expressionMap.onConflict : ""}`;
if (this.expressionMap.onUpdate) {
Expand Down
13 changes: 13 additions & 0 deletions test/github-issues/4513/entity/User.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Entity, PrimaryColumn, Column } from "../../../../src";

@Entity()
export class User {
@PrimaryColumn()
name: string;

@PrimaryColumn()
email: string;

@Column()
age: number;
}
140 changes: 140 additions & 0 deletions test/github-issues/4513/issue-4513.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import "reflect-metadata";
import { createTestingConnections, closeTestingConnections, reloadTestingDatabases } from "../../utils/test-utils";
import { Connection } from "../../../src/connection/Connection";
import { User } from "./entity/User";

describe("github issues > #4513 CockroachDB support for onConflict", () => {

let connections: Connection[];
before(async () => connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
schemaCreate: true,
dropSchema: true,
enabledDrivers: ["cockroachdb"]
}));
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));

it("should insert if no conflict", () => Promise.all(connections.map(async connection => {
const user1 = new User();
user1.name = "example";
user1.email = "example@example.com";
user1.age = 30;

await connection.createQueryBuilder()
.insert()
.into(User)
.values(user1)
.execute();

const user2 = new User();
user2.name = "example2";
user2.email = "example2@example.com";
user2.age = 42;

await connection.createQueryBuilder()
.insert()
.into(User)
.values(user2)
.onConflict(`("name", "email") DO NOTHING`)
.execute();

await connection.manager.find(User).should.eventually.have.lengthOf(2);
})));

it("should update on conflict with do update", () => Promise.all(connections.map(async connection => {
const user1 = new User();
user1.name = "example";
user1.email = "example@example.com";
user1.age = 30;

await connection.createQueryBuilder()
.insert()
.into(User)
.values(user1)
.execute();

const user2 = new User();
user2.name = "example";
user2.email = "example@example.com";
user2.age = 42;

await connection.createQueryBuilder()
.insert()
.into(User)
.values(user2)
.onConflict(`("name", "email") DO UPDATE SET age = EXCLUDED.age`)
.execute();

await connection.manager.findOne(User, { name: "example", email: "example@example.com" }).should.eventually.be.eql({
name: "example",
email: "example@example.com",
age: 42,
});
})));

it("should not update on conflict with do nothing", () => Promise.all(connections.map(async connection => {
const user1 = new User();
user1.name = "example";
user1.email = "example@example.com";
user1.age = 30;

await connection.createQueryBuilder()
.insert()
.into(User)
.values(user1)
.execute();

const user2 = new User();
user2.name = "example";
user2.email = "example@example.com";
user2.age = 42;

await connection.createQueryBuilder()
.insert()
.into(User)
.values(user2)
.onConflict(`("name", "email") DO NOTHING`)
.execute();

await connection.manager.findOne(User, { name: "example", email: "example@example.com" }).should.eventually.be.eql({
name: "example",
email: "example@example.com",
age: 30,
});
})));

it("should update with orUpdate", () => Promise.all(connections.map(async connection => {
const user1 = new User();
user1.name = "example";
user1.email = "example@example.com";
user1.age = 30;

await connection.createQueryBuilder()
.insert()
.into(User)
.values(user1)
.execute();

const user2 = new User();
user2.name = "example";
user2.email = "example@example.com";
user2.age = 42;

await connection.createQueryBuilder()
.insert()
.into(User)
.values(user2)
.orUpdate({
conflict_target: ["name", "email"],
overwrite: ["age"],
})
.execute();

await connection.manager.findOne(User, { name: "example", email: "example@example.com" }).should.eventually.be.eql({
name: "example",
email: "example@example.com",
age: 42,
});
})));
});

0 comments on commit db8074a

Please sign in to comment.