Skip to content

Commit

Permalink
feat: add support for cube array for PostgreSQL (#4848)
Browse files Browse the repository at this point in the history
* Add test case for arity 0 cubes

* Filter out empty string cube values during hydration

* WIP

* Update regex for cube array

* Remove arity 0 test

* Revert formatting changes

* Fix styling errors

* Update regex and comment for cube-array

* Code refactoring
  • Loading branch information
marlenekoh authored and pleerock committed Oct 13, 2019
1 parent 7882ec5 commit 154a441
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 20 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 28 additions & 2 deletions src/driver/postgres/PostgresDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,10 @@ export class PostgresDriver implements Driver {
return DateUtils.simpleJsonToString(value);

} else if (columnMetadata.type === "cube") {
return `(${value.join(", ")})`;
if (columnMetadata.isArray) {
return `{${value.map((cube: number[]) => `"(${cube.join(",")})"`).join(",")}}`;
}
return `(${value.join(",")})`;

} else if (
(
Expand Down Expand Up @@ -505,7 +508,30 @@ export class PostgresDriver implements Driver {
value = DateUtils.stringToSimpleJson(value);

} else if (columnMetadata.type === "cube") {
value = value.replace(/[\(\)\s]+/g, "").split(",").map(Number);
value = value.replace(/[\(\)\s]+/g, ""); // remove whitespace
if (columnMetadata.isArray) {
/**
* Strips these groups from `{"1,2,3","",NULL}`:
* 1. ["1,2,3", undefined] <- cube of arity 3
* 2. ["", undefined] <- cube of arity 0
* 3. [undefined, "NULL"] <- NULL
*/
const regexp = /(?:\"((?:[\d\s\.,])*)\")|(?:(NULL))/g;
const unparsedArrayString = value;

value = [];
let cube: RegExpExecArray | null = null;
// Iterate through all regexp matches for cubes/null in array
while ((cube = regexp.exec(unparsedArrayString)) !== null) {
if (cube[1] !== undefined) {
value.push(cube[1].split(",").filter(Boolean).map(Number));
} else {
value.push(undefined);
}
}
} else {
value = value.split(",").filter(Boolean).map(Number);
}

} else if (columnMetadata.type === "enum" || columnMetadata.type === "simple-enum" ) {
if (columnMetadata.isArray) {
Expand Down
50 changes: 36 additions & 14 deletions test/functional/cube/postgres/cube-postgres.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,18 @@ describe("cube-postgres", () => {
expect(schema).not.to.be.undefined;
const cubeColumn = schema!.columns.find(
tableColumn =>
tableColumn.name === "color" &&
tableColumn.type === "cube"
tableColumn.name === "mainColor" &&
tableColumn.type === "cube" &&
!tableColumn.isArray
);
expect(cubeColumn).to.not.be.undefined;
const cubeArrayColumn = schema!.columns.find(
tableColumn =>
tableColumn.name === "colors" &&
tableColumn.type === "cube" &&
tableColumn.isArray
);
expect(cubeArrayColumn).to.not.be.undefined;
})
));

Expand All @@ -41,11 +49,11 @@ describe("cube-postgres", () => {
const color = [255, 0, 0];
const postRepo = connection.getRepository(Post);
const post = new Post();
post.color = color;
post.mainColor = color;
const persistedPost = await postRepo.save(post);
const foundPost = await postRepo.findOne(persistedPost.id);
expect(foundPost).to.exist;
expect(foundPost!.color).to.deep.equal(color);
expect(foundPost!.mainColor).to.deep.equal(color);
})
));

Expand All @@ -56,17 +64,17 @@ describe("cube-postgres", () => {
const color2 = [0, 255, 0];
const postRepo = connection.getRepository(Post);
const post = new Post();
post.color = color;
post.mainColor = color;
const persistedPost = await postRepo.save(post);

await postRepo.update(
{ id: persistedPost.id },
{ color: color2 }
{ mainColor: color2 }
);

const foundPost = await postRepo.findOne(persistedPost.id);
expect(foundPost).to.exist;
expect(foundPost!.color).to.deep.equal(color2);
expect(foundPost!.mainColor).to.deep.equal(color2);
})
));

Expand All @@ -77,15 +85,15 @@ describe("cube-postgres", () => {
const color2 = [0, 255, 0];
const postRepo = connection.getRepository(Post);
const post = new Post();
post.color = color;
post.mainColor = color;
const persistedPost = await postRepo.save(post);

persistedPost.color = color2;
persistedPost.mainColor = color2;
await postRepo.save(persistedPost);

const foundPost = await postRepo.findOne(persistedPost.id);
expect(foundPost).to.exist;
expect(foundPost!.color).to.deep.equal(color2);
expect(foundPost!.mainColor).to.deep.equal(color2);
})
));

Expand All @@ -97,20 +105,34 @@ describe("cube-postgres", () => {
const color3 = [255, 255, 255];

const post1 = new Post();
post1.color = color1;
post1.mainColor = color1;
const post2 = new Post();
post2.color = color2;
post2.mainColor = color2;
const post3 = new Post();
post3.color = color3;
post3.mainColor = color3;
await connection.manager.save([post1, post2, post3]);

const posts = await connection.manager
.createQueryBuilder(Post, "post")
.orderBy("color <-> '(0, 255, 0)'", "DESC")
.orderBy("\"mainColor\" <-> '(0, 255, 0)'", "DESC")
.getMany();

const postIds = posts.map(post => post.id);
expect(postIds).to.deep.equal([post1.id, post3.id, post2.id]);
})
));

it("should persist cube array correctly", () =>
Promise.all(
connections.map(async connection => {
const colors = [[255, 0, 0], [255, 255, 0]];
const postRepo = connection.getRepository(Post);
const post = new Post();
post.colors = colors;
const persistedPost = await postRepo.save(post);
const foundPost = await postRepo.findOne(persistedPost.id);
expect(foundPost).to.exist;
expect(foundPost!.colors).to.deep.equal(colors);
})
));
});
11 changes: 8 additions & 3 deletions test/functional/cube/postgres/entity/Post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@ import {Column} from "../../../../../src/decorator/columns/Column";

@Entity()
export class Post {

@PrimaryGeneratedColumn()
id: number;

@Column("cube", {
nullable: true
nullable: true
})
mainColor: number[];

@Column("cube", {
nullable: true,
array: true
})
color: number[];
colors: number[][];
}

0 comments on commit 154a441

Please sign in to comment.