From 033094cf30c40c5964adea18c3ab24469fbc9348 Mon Sep 17 00:00:00 2001 From: melohagan <101575380+melohagan@users.noreply.github.com> Date: Mon, 19 Dec 2022 18:12:05 +0000 Subject: [PATCH] SQL server relationship fix for tables in schema (#9103) * Add schema to LEFT JOIN * lint --- packages/server/src/integrations/base/sql.ts | 20 +++- .../server/src/integrations/tests/sql.spec.ts | 92 +++++++++++++++++++ 2 files changed, 107 insertions(+), 5 deletions(-) diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index 43ebc8b1dd..a2318eff12 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -313,7 +313,8 @@ class InternalBuilder { addRelationships( query: KnexQuery, fromTable: string, - relationships: RelationshipsJson[] | undefined + relationships: RelationshipsJson[] | undefined, + schema: string | undefined ): KnexQuery { if (!relationships) { return query @@ -337,9 +338,13 @@ class InternalBuilder { } for (let [key, relationships] of Object.entries(tableSets)) { const { toTable, throughTable } = JSON.parse(key) + const toTableWithSchema = schema ? `${schema}.${toTable}` : toTable + const throughTableWithSchema = schema + ? `${schema}.${throughTable}` + : throughTable if (!throughTable) { // @ts-ignore - query = query.leftJoin(toTable, function () { + query = query.leftJoin(toTableWithSchema, function () { for (let relationship of relationships) { const from = relationship.from, to = relationship.to @@ -350,7 +355,7 @@ class InternalBuilder { } else { query = query // @ts-ignore - .leftJoin(throughTable, function () { + .leftJoin(throughTableWithSchema, function () { for (let relationship of relationships) { const fromPrimary = relationship.fromPrimary const from = relationship.from @@ -362,7 +367,7 @@ class InternalBuilder { ) } }) - .leftJoin(toTable, function () { + .leftJoin(toTableWithSchema, function () { for (let relationship of relationships) { const toPrimary = relationship.toPrimary const to = relationship.to @@ -456,7 +461,12 @@ class InternalBuilder { preQuery = this.addSorting(preQuery, json) } // handle joins - query = this.addRelationships(preQuery, tableName, relationships) + query = this.addRelationships( + preQuery, + tableName, + relationships, + endpoint.schema + ) return this.addFilters(query, filters, { relationship: true }) } diff --git a/packages/server/src/integrations/tests/sql.spec.ts b/packages/server/src/integrations/tests/sql.spec.ts index 421b8535d4..2e45f0754b 100644 --- a/packages/server/src/integrations/tests/sql.spec.ts +++ b/packages/server/src/integrations/tests/sql.spec.ts @@ -51,6 +51,72 @@ function generateDeleteJson(table = TABLE_NAME, filters = {}) { } } +function generateRelationshipJson(config: { schema?: string } = {}) { + return { + endpoint: { + datasourceId: "Postgres", + entityId: "brands", + operation: "READ", + schema: config.schema, + }, + resource: { + fields: [ + "brands.brand_id", + "brands.brand_name", + "products.product_id", + "products.product_name", + "products.brand_id", + ], + }, + filters: {}, + sort: {}, + paginate: {}, + relationships: [ + { + from: "brand_id", + to: "brand_id", + tableName: "products", + column: "products", + }, + ], + extra: { idFilter: {} }, + } +} + +function generateManyRelationshipJson(config: { schema?: string } = {}) { + return { + endpoint: { + datasourceId: "Postgres", + entityId: "stores", + operation: "READ", + schema: config.schema, + }, + resource: { + fields: [ + "stores.store_id", + "stores.store_name", + "products.product_id", + "products.product_name", + ], + }, + filters: {}, + sort: {}, + paginate: {}, + relationships: [ + { + from: "store_id", + to: "product_id", + tableName: "products", + column: "products", + through: "stocks", + fromPrimary: "store_id", + toPrimary: "product_id", + }, + ], + extra: { idFilter: {} }, + } +} + describe("SQL query builder", () => { const limit = 500 const client = SqlClient.POSTGRES @@ -425,4 +491,30 @@ describe("SQL query builder", () => { sql: `select * from (select * from \"${TABLE_NAME}\" where \"${TABLE_NAME}\".\"age\"::jsonb ?| array [20,25] and \"${TABLE_NAME}\".\"name\"::jsonb ?| array ['John','Mary'] limit $1) as \"${TABLE_NAME}\"`, }) }) + + it("should add the schema to the LEFT JOIN", () => { + const query = sql._query(generateRelationshipJson({ schema: "production" })) + expect(query).toEqual({ + bindings: [500, 5000], + sql: `select "brands"."brand_id" as "brands.brand_id", "brands"."brand_name" as "brands.brand_name", "products"."product_id" as "products.product_id", "products"."product_name" as "products.product_name", "products"."brand_id" as "products.brand_id" from (select * from "production"."brands" limit $1) as "brands" left join "production"."products" on "brands"."brand_id" = "products"."brand_id" limit $2`, + }) + }) + + it("should handle if the schema is not present when doing a LEFT JOIN", () => { + const query = sql._query(generateRelationshipJson()) + expect(query).toEqual({ + bindings: [500, 5000], + sql: `select "brands"."brand_id" as "brands.brand_id", "brands"."brand_name" as "brands.brand_name", "products"."product_id" as "products.product_id", "products"."product_name" as "products.product_name", "products"."brand_id" as "products.brand_id" from (select * from "brands" limit $1) as "brands" left join "products" on "brands"."brand_id" = "products"."brand_id" limit $2`, + }) + }) + + it("should add the schema to both the toTable and throughTable in many-to-many join", () => { + const query = sql._query( + generateManyRelationshipJson({ schema: "production" }) + ) + expect(query).toEqual({ + bindings: [500, 5000], + sql: `select "stores"."store_id" as "stores.store_id", "stores"."store_name" as "stores.store_name", "products"."product_id" as "products.product_id", "products"."product_name" as "products.product_name" from (select * from "production"."stores" limit $1) as "stores" left join "production"."stocks" on "stores"."store_id" = "stocks"."store_id" left join "production"."products" on "products"."product_id" = "stocks"."product_id" limit $2`, + }) + }) })