From a4900ae15feb6727f085cbeae09000566b15081e Mon Sep 17 00:00:00 2001 From: Joren Vandeweyer Date: Fri, 29 Dec 2023 15:09:30 +0100 Subject: [PATCH] fix: extend GiST index with range types for Postgres driver (#10572) * fix: extend spatial column types for postgres driver Extend spatial column type with range types for postgres. This fixes a bug when using spatial indices. Closes: #10567 * format * remove only from test, ready for pr * changed a way how we determine index type --------- Co-authored-by: Dmitry Zotov --- src/driver/postgres/PostgresQueryRunner.ts | 10 ++-- .../10567/entity/address-history.ts | 48 +++++++++++++++++++ test/github-issues/10567/issue-10567.ts | 48 +++++++++++++++++++ 3 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 test/github-issues/10567/entity/address-history.ts create mode 100644 test/github-issues/10567/issue-10567.ts diff --git a/src/driver/postgres/PostgresQueryRunner.ts b/src/driver/postgres/PostgresQueryRunner.ts index aec045b6c..5adf541d8 100644 --- a/src/driver/postgres/PostgresQueryRunner.ts +++ b/src/driver/postgres/PostgresQueryRunner.ts @@ -3311,13 +3311,14 @@ export class PostgresQueryRunner const indicesSql = `SELECT "ns"."nspname" AS "table_schema", "t"."relname" AS "table_name", "i"."relname" AS "constraint_name", "a"."attname" AS "column_name", ` + `CASE "ix"."indisunique" WHEN 't' THEN 'TRUE' ELSE'FALSE' END AS "is_unique", pg_get_expr("ix"."indpred", "ix"."indrelid") AS "condition", ` + - `"types"."typname" AS "type_name" ` + + `"types"."typname" AS "type_name", "am"."amname" AS "index_type" ` + `FROM "pg_class" "t" ` + `INNER JOIN "pg_index" "ix" ON "ix"."indrelid" = "t"."oid" ` + `INNER JOIN "pg_attribute" "a" ON "a"."attrelid" = "t"."oid" AND "a"."attnum" = ANY ("ix"."indkey") ` + `INNER JOIN "pg_namespace" "ns" ON "ns"."oid" = "t"."relnamespace" ` + `INNER JOIN "pg_class" "i" ON "i"."oid" = "ix"."indexrelid" ` + `INNER JOIN "pg_type" "types" ON "types"."oid" = "a"."atttypid" ` + + `INNER JOIN "pg_am" "am" ON "i"."relam" = "am"."oid" ` + `LEFT JOIN "pg_constraint" "cnst" ON "cnst"."conname" = "i"."relname" ` + `WHERE "t"."relkind" IN ('r', 'p') AND "cnst"."contype" IS NULL AND (${constraintsCondition})` @@ -3939,12 +3940,7 @@ export class PostgresQueryRunner columnNames: indices.map((i) => i["column_name"]), isUnique: constraint["is_unique"] === "TRUE", where: constraint["condition"], - isSpatial: indices.every( - (i) => - this.driver.spatialTypes.indexOf( - i["type_name"], - ) >= 0, - ), + isSpatial: constraint["index_type"] === "gist", isFulltext: false, }) }) diff --git a/test/github-issues/10567/entity/address-history.ts b/test/github-issues/10567/entity/address-history.ts new file mode 100644 index 000000000..378b04e3d --- /dev/null +++ b/test/github-issues/10567/entity/address-history.ts @@ -0,0 +1,48 @@ +import { Column, Entity, Index, PrimaryGeneratedColumn } from "../../../../src" + +@Entity() +export class AddressHistory { + @PrimaryGeneratedColumn("uuid") + uuid: string + + @Index() + @Column({ type: "uuid" }) + entityUuid: string + + @Index() + @Column({ type: "uuid" }) + addressUuid: string + + @Index({ spatial: true }) + @Column({ type: "int4range" }) + int4range: string + + @Index({ spatial: true }) + @Column({ type: "int8range" }) + int8range: string + + @Index({ spatial: true }) + @Column({ type: "numrange" }) + numrange: string + + @Index({ spatial: true }) + @Column({ type: "tsrange" }) + tsrange: string + + @Index({ spatial: true }) + @Column({ type: "tstzrange" }) + tstzrange: string + + @Index({ spatial: true }) + @Column({ type: "daterange" }) + daterange: string + + @Index({ spatial: true }) + @Column({ + type: "geometry", + spatialFeatureType: "Point", + srid: 4326, + nullable: true, + }) + point: string +} diff --git a/test/github-issues/10567/issue-10567.ts b/test/github-issues/10567/issue-10567.ts new file mode 100644 index 000000000..b2a03ae14 --- /dev/null +++ b/test/github-issues/10567/issue-10567.ts @@ -0,0 +1,48 @@ +import "reflect-metadata" +import { + createTestingConnections, + closeTestingConnections, +} from "../../utils/test-utils" +import { DataSource } from "../../../src/index.js" + +describe("github issues > #10567 Postgres: Gist index on daterange column recreated every migration", () => { + let dataSources: DataSource[] + + before( + async () => + (dataSources = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + schemaCreate: false, + dropSchema: true, + enabledDrivers: ["postgres"], + })), + ) + + after(() => closeTestingConnections(dataSources)) + + it("can recognize model changes", () => + Promise.all( + dataSources.map(async (dataSource) => { + const sqlInMemory = await dataSource.driver + .createSchemaBuilder() + .log() + + sqlInMemory.upQueries.length.should.be.greaterThan(0) + sqlInMemory.downQueries.length.should.be.greaterThan(0) + }), + )) + + it("does not generate when no model changes", () => + Promise.all( + dataSources.map(async (dataSource) => { + await dataSource.driver.createSchemaBuilder().build() + + const sqlInMemory = await dataSource.driver + .createSchemaBuilder() + .log() + + sqlInMemory.upQueries.length.should.be.equal(0) + sqlInMemory.downQueries.length.should.be.equal(0) + }), + )) +})