Skip to content

Commit

Permalink
fix: allow for complex jsonb primary key columns (#6834)
Browse files Browse the repository at this point in the history
* fix: allow for complex jsonb primary key columns

When using PrimaryColumn with a 'jsonb' type column
( on a postgres database ) the RawSqlResultsToEntityTransformer
would simply convert the key to '[object Object]' instead of a
unique value based on the key value. It would then wrongly consider each
entity as having the same key.

To allow for complex keys the transformer now uses JSON.stringify()
to convert the keys value if they are of type obejct to a unique
string that can be compared
to other entities.

fixes #6833

* test: add tests for jsonb primarykey columns

These tests verify that Entities with jsonb primary columns are correctly
converted to Entites
  • Loading branch information
maddimax committed Oct 6, 2020
1 parent 08ec0a8 commit f95e9d8
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 0 deletions.
Expand Up @@ -70,6 +70,10 @@ export class RawSqlResultsToEntityTransformer {
return keyValue.toString("hex");
}

if (typeof keyValue === "object") {
return JSON.stringify(keyValue);
}

return keyValue;
}).join("_"); // todo: check partial

Expand Down
12 changes: 12 additions & 0 deletions test/github-issues/6833/entity/test.ts
@@ -0,0 +1,12 @@
import { Entity, PrimaryColumn } from "../../../../src";

export class MyId {
first: number;
second: number;
}

@Entity({ name: "jsonb_key_tests" })
export class JSONBKeyTest {
@PrimaryColumn("jsonb")
id: MyId;
}
81 changes: 81 additions & 0 deletions test/github-issues/6833/issue-6833.ts
@@ -0,0 +1,81 @@
import "reflect-metadata";
import {
createTestingConnections,
closeTestingConnections,
reloadTestingDatabases,
} from "../../utils/test-utils";
import { Connection } from "../../../src/connection/Connection";
import { expect } from "chai";
import { JSONBKeyTest } from "./entity/test";

describe("github issues > #6833 Entities with JSON key columns are incorrectly grouped", () => {
let connections: Connection[];
before(async () => connections = await createTestingConnections({
entities: [JSONBKeyTest],
dropSchema: true,
schemaCreate: true,
enabledDrivers: ["postgres"]
}));
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));

it("jsonB keys are correctly resolved", () => Promise.all(connections.map(async connection => {
await connection.transaction(async manager => {
await manager.save(manager.create(JSONBKeyTest, { id: { first: 1, second: 2 } }));
await manager.save(manager.create(JSONBKeyTest, { id: { first: 1, second: 3 } }));

const entities = await manager.createQueryBuilder(JSONBKeyTest, "json_test").select().getMany();
expect(entities.length).to.equal(2);
});
})));

it("jsonB keys can be found", () => Promise.all(connections.map(async connection => {
await connection.transaction(async manager => {
await manager.save(manager.create(JSONBKeyTest, { id: { first: 3, second: 3 } }));
await manager.save(manager.create(JSONBKeyTest, { id: { first: 4, second: 3 } }));

const entities = await manager.find(JSONBKeyTest, { where: { id: { first: 3, second: 3 } } } );
expect(entities.length).to.equal(1);
expect(entities[0].id).to.deep.equal({ first: 3, second: 3 });
});
})));

it("jsonB keys can be found with IN", () => Promise.all(connections.map(async connection => {
await connection.transaction(async manager => {
await manager.save(manager.create(JSONBKeyTest, { id: { first: 3, second: 3 } }));
await manager.save(manager.create(JSONBKeyTest, { id: { first: 4, second: 3 } }));
await manager.save(manager.create(JSONBKeyTest, { id: { first: 5, second: 3 } }));
await manager.save(manager.create(JSONBKeyTest, { id: { first: 6, second: 4 } }));

const entities = await manager
.createQueryBuilder(JSONBKeyTest, "json_test")
.select()
.where("id IN (:...ids)", { ids: [{first: 5, second: 3}, {first: 6, second: 4}]})
.getMany();
expect(entities.length).to.equal(2);
expect(entities[0].id).to.deep.equal({ first: 5, second: 3 });
expect(entities[1].id).to.deep.equal({ first: 6, second: 4 });
});
})));

it("jsonB keys can be found regardless of order", () => Promise.all(connections.map(async connection => {
await connection.transaction(async manager => {
await manager.save(manager.create(JSONBKeyTest, { id: { first: 3, second: 3 } }));
await manager.save(manager.create(JSONBKeyTest, { id: { first: 4, second: 3 } }));
await manager.save(manager.create(JSONBKeyTest, { id: { first: 5, second: 3 } }));
await manager.save(manager.create(JSONBKeyTest, { id: { first: 6, second: 4 } }));


const payload = { second: 2, first: 1 };
await manager.save(manager.create(JSONBKeyTest, { id: payload }));
const entities = await manager.find(JSONBKeyTest, { where: { id: payload } });
expect(entities.length).to.equal(1);
expect(entities[0].id).to.deep.equal({ first: 1, second: 2 });

const entitiesOtherOrder = await manager.find(JSONBKeyTest, { where: { id: {first: 1, second: 2} } });
expect(entitiesOtherOrder.length).to.equal(1);
expect(entitiesOtherOrder[0].id).to.deep.equal({ first: 1, second: 2 });

});
})));
});

0 comments on commit f95e9d8

Please sign in to comment.