Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Grant/bru-1077 #45

Merged
merged 4 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
Warnings:

- You are about to drop the column `schema` on the `database` table. All the data in the column will be lost.

*/
-- AlterTable
ALTER TABLE "database" DROP COLUMN "schema";
1 change: 0 additions & 1 deletion backend/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ model database {
external_name String
connection_url String
encryption_vector String
schema String
organization_id String
require_ssl Boolean
tables table[]
Expand Down
11 changes: 0 additions & 11 deletions backend/src/databases/databases.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,24 +111,13 @@ export class DatabasesService {
data: {
name: createDatabaseObj.name,
external_name: externalName,
schema: createDatabaseObj.schema ?? "public",
require_ssl: createDatabaseObj.require_ssl,
connection_url: cypherText,
encryption_vector: encryptionVector,
organization_id: orgId,
},
});

// Get current schemas and assign default schema for database
const schemas = await this.findAllSchemas(database.id);

if (schemas.length > 0) {
const defaultSchema = schemas.includes("public") ? "public" : schemas[0];
await this.updateDatabase(database.id, {
schema: defaultSchema,
});
}

assert(database, "Database creation error");

return database;
Expand Down
1 change: 0 additions & 1 deletion backend/src/definitions/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ export const DatabaseSchema = z.object({
connection_url: z.string(),
encryption_vector: z.string(),
organization_id: z.string(),
schema: z.string(),
require_ssl: z.boolean(),
created_at: z.date(),
updated_at: z.date(),
Expand Down
48 changes: 22 additions & 26 deletions backend/src/postgres-adapter/postgres-adapter.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export class PostgresAdapterService {

return pool.connect();
}

async run(createDatabaseQueryDto: CreateDatabaseQueryDto) {
const client = await this.getClientForDatabase(
createDatabaseQueryDto.databaseId,
Expand All @@ -90,32 +91,33 @@ export class PostgresAdapterService {

async getAllTableSchema(
databaseId: string,
): Promise<Record<string, Record<string, ExternalColumn>>> {
): Promise<Record<string, Record<string, Record<string, ExternalColumn>>>> {
const database = await this.databaseService.findOne(databaseId);
const client = await this.getClientForDatabase(databaseId);
assert(database, "Database not found");

try {
const result = await client.query(
`SELECT
*
FROM
information_schema.columns
WHERE
table_schema = $1;`,
[database.schema || "public"],
`SELECT * FROM information_schema.columns`,
);

// map returned columns into tables
// Build a map of schemata to tables to columns
const columns = result.rows;
const tables = {};
const columnMap = {};
for (const column of columns) {
if (!tables[column.table_name]) {
tables[column.table_name] = {};
if (!columnMap[column.table_schema]) {
columnMap[column.table_schema] = {};
}

if (!columnMap[column.table_schema][column.table_name]) {
columnMap[column.table_schema][column.table_name] = {};
}
tables[column.table_name][column.column_name] = columnMapping(column);

columnMap[column.table_schema][column.table_name][column.column_name] =
columnMapping(column);
}
return tables;

return columnMap;
} catch (e) {
console.log(e);
throw e;
Expand All @@ -131,14 +133,12 @@ export class PostgresAdapterService {

try {
const result = await client.query(
`select schema_name
from information_schema.schemata`,
`SELECT schema_name FROM information_schema.schemata`,
);
const columns = result.rows;
const schemata = columns.map((column) => column.schema_name);

const schemas = columns.map((column) => column.schema_name);

return schemas;
return schemata;
} catch (e) {
console.log(e);
throw e;
Expand All @@ -158,7 +158,9 @@ export class PostgresAdapterService {
tc.constraint_name,
tc.constraint_type,
tc.table_name,
tc.table_schema,
kcu.column_name,
ccu.table_schema AS foreign_schema_name,
ccu.table_name AS foreign_table_name,
ccu.column_name AS foreign_column_name
FROM
Expand All @@ -172,13 +174,7 @@ export class PostgresAdapterService {
ON tc.constraint_name = ccu.constraint_name
AND tc.table_schema = ccu.table_schema
WHERE
tc.constraint_type IN ('FOREIGN KEY', 'PRIMARY KEY', 'UNIQUE')
AND tc.table_schema = $1
ORDER BY
tc.table_name,
tc.constraint_type,
kcu.column_name;`,
[database.schema || "public"],
tc.constraint_type IN ('FOREIGN KEY', 'PRIMARY KEY', 'UNIQUE');`,
);

return result.rows;
Expand Down
85 changes: 47 additions & 38 deletions backend/src/relations/relations.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,53 +57,62 @@ export class RelationsService {
_.forEach(externalConstraints, (constraint) => {
if (constraint.constraint_type === "FOREIGN KEY") {
const table1 = _.find(tables, (table) => {
return table.external_name === constraint.foreign_table_name;
return (
table.schema === constraint.foreign_schema_name &&
table.external_name === constraint.foreign_table_name
);
});
assert(table1, `Table not found: ${constraint.foreign_table_name}`);

const table2 = _.find(tables, (table) => {
return table.external_name === constraint.table_name;
});
assert(table2, `Table not found: ${constraint.table_name}`);

// To determine the relation type, check for uniqueness of the current column
// If the column is unique, then the relation is one-to-one (otherwise it’s one-to-many)
const isUnique = _.some(externalConstraints, (c) => {
return (
c.table_name === constraint.table_name &&
c.column_name === constraint.column_name &&
(c.constraint_type === "UNIQUE" ||
c.constraint_type === "PRIMARY KEY")
table.schema === constraint.table_schema &&
table.external_name === constraint.table_name
);
});

const relationType = (
isUnique ? "one_to_one" : "one_to_many"
) as RelationType;

const foundConstraint = _.find(parsedExistingRelations, (relation) => {
return (
relation.table_1 === table1.id &&
relation.table_2 === table2.id &&
relation.column_1 === constraint.foreign_column_name &&
relation.column_2 === constraint.column_name &&
relation.type === relationType
if (table1 && table2) {
// To determine the relation type, check for uniqueness of the current column
// If the column is unique, then the relation is one-to-one (otherwise it’s one-to-many)
const isUnique = _.some(externalConstraints, (c) => {
return (
c.table_name === constraint.table_name &&
c.column_name === constraint.column_name &&
(c.constraint_type === "UNIQUE" ||
c.constraint_type === "PRIMARY KEY")
);
});

const relationType = (
isUnique ? "one_to_one" : "one_to_many"
) as RelationType;

const foundConstraint = _.find(
parsedExistingRelations,
(relation) => {
return (
relation.table_1 === table1.id &&
relation.table_2 === table2.id &&
relation.column_1 === constraint.foreign_column_name &&
relation.column_2 === constraint.column_name &&
relation.type === relationType
);
},
);
});

// If the relation isn't found, add it in the db
if (!foundConstraint) {
const newRelation = {
database_id: databaseId,
type: relationType,
generated: true,
table_1: table1.id,
table_2: table2.id,
column_1: constraint.foreign_column_name,
column_2: constraint.column_name,
};

promises.push(this.create(newRelation));
// If the relation isn't found, add it in the db
if (!foundConstraint) {
const newRelation = {
database_id: databaseId,
type: relationType,
generated: true,
table_1: table1.id,
table_2: table2.id,
column_1: constraint.foreign_column_name,
column_2: constraint.column_name,
};

promises.push(this.create(newRelation));
}
}
}
});
Expand Down
Loading
Loading