Skip to content

Commit

Permalink
show only the selected database for outerbase cloud
Browse files Browse the repository at this point in the history
  • Loading branch information
invisal committed Mar 4, 2025
1 parent 7acea94 commit ab7055f
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 29 deletions.
28 changes: 16 additions & 12 deletions src/app/(outerbase)/w/[workspaceId]/[baseId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {
import DataCatalogExtension from "@/extensions/data-catalog";
import OuterbaseExtension from "@/extensions/outerbase";
import { getOuterbaseBase } from "@/outerbase-cloud/api";
import { OuterbaseAPISource } from "@/outerbase-cloud/api-type";
import { OuterbaseAPIBaseCredential } from "@/outerbase-cloud/api-type";
import { getOuterbaseBaseCredential } from "@/outerbase-cloud/api-workspace";
import DataCatalogOuterbaseDriver from "@/outerbase-cloud/data-catalog-driver";
import { OuterbaseMySQLDriver } from "@/outerbase-cloud/database/mysql";
import { OuterbasePostgresDriver } from "@/outerbase-cloud/database/postgresql";
Expand All @@ -26,32 +27,35 @@ export default function OuterbaseSourcePage() {
baseId: string;
}>();
const [name, setName] = useState<string>("");
const [source, setSource] = useState<OuterbaseAPISource>();
const [credential, setCredential] = useState<OuterbaseAPIBaseCredential>();

useEffect(() => {
if (!workspaceId) return;
if (!baseId) return;

getOuterbaseBase(workspaceId, baseId).then((base) => {
if (!base) return;
setSource(base.sources[0]);

setName(base.name);
getOuterbaseBaseCredential(workspaceId, base.sources[0]?.id ?? "").then(
setCredential
);
});
}, [workspaceId, baseId]);

const savedDocDriver = useMemo(() => {
if (!workspaceId || !source?.id || !baseId) return null;
return new OuterbaseQueryDriver(workspaceId, baseId, source.id);
}, [workspaceId, baseId, source?.id]);
if (!workspaceId || !credential?.id || !baseId) return null;
return new OuterbaseQueryDriver(workspaceId, baseId, credential.id);
}, [workspaceId, baseId, credential?.id]);

const [outerbaseDriver, extensions] = useMemo(() => {
if (!workspaceId || !source) return [null, null];
if (!workspaceId || !credential) return [null, null];

const dialect = source.type;
const dialect = credential.type;
const outerbaseConfig = {
workspaceId,
sourceId: source.id,
baseId: source.base_id,
sourceId: credential.id,
baseId,
token: localStorage.getItem("ob-token") ?? "",
};

Expand All @@ -70,7 +74,7 @@ export default function OuterbaseSourcePage() {
];
} else if (dialect === "mysql") {
return [
new OuterbaseMySQLDriver(outerbaseConfig),
new OuterbaseMySQLDriver(outerbaseConfig, credential.database),
new StudioExtensionManager([
...createMySQLExtensions(),
...outerbaseSpecifiedDrivers,
Expand All @@ -85,7 +89,7 @@ export default function OuterbaseSourcePage() {
...outerbaseSpecifiedDrivers,
]),
];
}, [workspaceId, source]);
}, [workspaceId, credential, baseId]);

if (!outerbaseDriver || !savedDocDriver) {
return <PageLoading>Loading Base ...</PageLoading>;
Expand Down
41 changes: 26 additions & 15 deletions src/drivers/mysql/mysql-driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@ function mapColumn(column: MySqlColumn): DatabaseTableColumn {
export default abstract class MySQLLikeDriver extends CommonSQLImplement {
columnTypeSelector: ColumnTypeSelector = MYSQL_DATA_TYPE_SUGGESTION;

// If this is specified, we only show the tables in this database
// Outerbase Cloud does not support the USE statement because it runs in non-interactive mode
// It does not make sense to show other databases.
selectedDatabase: string = "";

escapeId(id: string) {
return `\`${id.replace(/`/g, "``")}\``;
}
Expand All @@ -138,14 +143,13 @@ export default abstract class MySQLLikeDriver extends CommonSQLImplement {

getFlags(): DriverFlags {
return {
defaultSchema: "",
optionalSchema: false,
defaultSchema: this.selectedDatabase,
optionalSchema: this.selectedDatabase ? true : false,
supportBigInt: false,
supportModifyColumn: true,
supportCreateUpdateTable: true,
supportCreateUpdateDatabase: true,
supportCreateUpdateDatabase: this.selectedDatabase ? false : true,
dialect: "mysql",

supportUseStatement: true,
supportRowId: false,
supportInsertReturning: false,
Expand All @@ -167,22 +171,29 @@ export default abstract class MySQLLikeDriver extends CommonSQLImplement {
}

async schemas(): Promise<DatabaseSchemas> {
const schemaSql =
"SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')";
const schemaSql = this.selectedDatabase
? `SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = ${this.escapeValue(this.selectedDatabase)}`
: "SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')";

const tableSql =
"SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE, DATA_LENGTH, INDEX_LENGTH FROM information_schema.tables WHERE TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')";
const tableSql = this.selectedDatabase
? `SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE, DATA_LENGTH, INDEX_LENGTH FROM information_schema.tables WHERE TABLE_SCHEMA = ${this.escapeValue(this.selectedDatabase)}`
: "SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE, DATA_LENGTH, INDEX_LENGTH FROM information_schema.tables WHERE TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')";

const columnSql =
"SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, COLUMN_TYPE, DATA_TYPE, EXTRA, COLUMN_KEY, IS_NULLABLE, COLUMN_DEFAULT FROM information_schema.columns WHERE TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')";
const columnSql = this.selectedDatabase
? `SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, COLUMN_TYPE, DATA_TYPE, EXTRA, COLUMN_KEY, IS_NULLABLE, COLUMN_DEFAULT FROM information_schema.columns WHERE TABLE_SCHEMA = ${this.escapeValue(this.selectedDatabase)}`
: "SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, COLUMN_TYPE, DATA_TYPE, EXTRA, COLUMN_KEY, IS_NULLABLE, COLUMN_DEFAULT FROM information_schema.columns WHERE TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')";

const constraintSql =
"SELECT TABLE_SCHEMA, TABLE_NAME, CONSTRAINT_NAME, CONSTRAINT_TYPE FROM information_schema.table_constraints WHERE TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys') AND CONSTRAINT_TYPE IN ('PRIMARY KEY', 'UNIQUE', 'FOREIGN KEY')";
const constraintSql = this.selectedDatabase
? `SELECT TABLE_SCHEMA, TABLE_NAME, CONSTRAINT_NAME, CONSTRAINT_TYPE FROM information_schema.table_constraints WHERE TABLE_SCHEMA = ${this.escapeValue(this.selectedDatabase)} AND CONSTRAINT_TYPE IN ('PRIMARY KEY', 'UNIQUE', 'FOREIGN KEY')`
: "SELECT TABLE_SCHEMA, TABLE_NAME, CONSTRAINT_NAME, CONSTRAINT_TYPE FROM information_schema.table_constraints WHERE TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys') AND CONSTRAINT_TYPE IN ('PRIMARY KEY', 'UNIQUE', 'FOREIGN KEY')";

const constraintColumnsSql = `SELECT CONSTRAINT_NAME, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, REFERENCED_TABLE_SCHEMA, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME FROM information_schema.key_column_usage WHERE TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')`;
const constraintColumnsSql = this.selectedDatabase
? `SELECT CONSTRAINT_NAME, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, REFERENCED_TABLE_SCHEMA, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME FROM information_schema.key_column_usage WHERE TABLE_SCHEMA = ${this.escapeValue(this.selectedDatabase)}`
: `SELECT CONSTRAINT_NAME, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, REFERENCED_TABLE_SCHEMA, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME FROM information_schema.key_column_usage WHERE TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')`;

const triggerSql =
"SELECT * from information_schema.triggers WHERE TRIGGER_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')";
const triggerSql = this.selectedDatabase
? `SELECT * from information_schema.triggers WHERE TRIGGER_SCHEMA = ${this.escapeValue(this.selectedDatabase)}`
: "SELECT * from information_schema.triggers WHERE TRIGGER_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')";

const result = await this.batch([
schemaSql,
Expand Down
4 changes: 4 additions & 0 deletions src/outerbase-cloud/api-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ export interface OuterbaseAPISourceInput {
connection_id?: string;
}

export interface OuterbaseAPIBaseCredential extends OuterbaseAPISourceInput {
id: string;
}

export interface OuterbaseAPISource {
model: "source";
type: string;
Expand Down
3 changes: 2 additions & 1 deletion src/outerbase-cloud/api-workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { mutate } from "swr";
import { requestOuterbase } from "./api";
import {
OuterbaseAPIBase,
OuterbaseAPIBaseCredential,
OuterbaseAPIConnection,
OuterbaseAPISource,
OuterbaseAPISourceInput,
Expand Down Expand Up @@ -103,7 +104,7 @@ export async function getOuterbaseBaseCredential(
workspaceId: string,
sourceId: string
) {
return await requestOuterbase<OuterbaseAPISourceInput>(
return await requestOuterbase<OuterbaseAPIBaseCredential>(
`/api/v1/workspace/${workspaceId}/source/${sourceId}/credential`,
"GET"
);
Expand Down
6 changes: 5 additions & 1 deletion src/outerbase-cloud/database/mysql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@ export class OuterbaseMySQLDriver extends MySQLLikeDriver {
};
}

constructor({ workspaceId, sourceId }: OuterbaseDatabaseConfig) {
constructor(
{ workspaceId, sourceId }: OuterbaseDatabaseConfig,
selectedDatabase?: string
) {
super();

this.selectedDatabase = selectedDatabase ?? "";
this.workspaceId = workspaceId;
this.sourceId = sourceId;
}
Expand Down

0 comments on commit ab7055f

Please sign in to comment.