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

Get schemas for non-Dolt dbs #24

Merged
merged 7 commits into from
Oct 31, 2023
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
19 changes: 16 additions & 3 deletions packages/graphql-server/schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,19 @@ type SchemaDiff {
numChangedSchemas: Int
}

type SchemaItem {
name: String!
type: SchemaType!
}

enum SchemaType {
View
Procedure
Event
Trigger
Table
}

type SqlSelect {
_id: ID!
databaseName: String!
Expand Down Expand Up @@ -227,10 +240,10 @@ type Query {
docOrDefaultDoc(refName: String!, databaseName: String!, docType: DocType): Doc
rowDiffs(offset: Int, databaseName: String!, fromCommitId: String!, toCommitId: String!, refName: String, tableName: String!, filterByRowType: DiffRowType): RowDiffList!
rows(refName: String!, databaseName: String!, tableName: String!, offset: Int): RowList!
doltSchemas(databaseName: String!, refName: String!): RowList!
views(databaseName: String!, refName: String!): RowList!
doltProcedures(databaseName: String!, refName: String!): RowList
schemaDiff(databaseName: String!, fromCommitId: String!, toCommitId: String!, refName: String, tableName: String!): SchemaDiff
doltSchemas(databaseName: String!, refName: String!): [SchemaItem!]!
views(databaseName: String!, refName: String!): [SchemaItem!]!
doltProcedures(databaseName: String!, refName: String!): [SchemaItem!]!
sqlSelect(refName: String!, databaseName: String!, queryString: String!): SqlSelect!
sqlSelectForCsvDownload(refName: String!, databaseName: String!, queryString: String!): String!
status(databaseName: String!, refName: String!): [Status!]!
Expand Down
2 changes: 2 additions & 0 deletions packages/graphql-server/src/resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { DocsResolver } from "./docs/doc.resolver";
import { RowDiffResolver } from "./rowDiffs/rowDiff.resolver";
import { RowResolver } from "./rows/row.resolver";
import { SchemaDiffResolver } from "./schemaDiffs/schemaDiff.resolver";
import { SchemaResolver } from "./schemas/schema.resolver";
import { SqlSelectResolver } from "./sqlSelects/sqlSelect.resolver";
import { StatusResolver } from "./status/status.resolver";
import { TableResolver } from "./tables/table.resolver";
Expand All @@ -24,6 +25,7 @@ const resolvers = [
RowDiffResolver,
RowResolver,
SchemaDiffResolver,
SchemaResolver,
SqlSelectResolver,
StatusResolver,
TableResolver,
Expand Down
5 changes: 1 addition & 4 deletions packages/graphql-server/src/rows/row.queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,10 @@ import { RawRows } from "../utils/commonTypes";

export const getRowsQuery = (
columns: RawRows,
hasWhereCause = false,
): { q: string; cols: string[] } => {
const cols = getPKColsForRowsQuery(columns);
return {
q: `SELECT * FROM ?? ${
hasWhereCause ? "WHERE type = ? " : ""
}${getOrderByFromCols(cols.length)}LIMIT ? OFFSET ?`,
q: `SELECT * FROM ?? ${getOrderByFromCols(cols.length)}LIMIT ? OFFSET ?`,
cols,
};
};
Expand Down
41 changes: 0 additions & 41 deletions packages/graphql-server/src/rows/row.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { Args, ArgsType, Field, Int, Query, Resolver } from "@nestjs/graphql";
import { handleTableNotFound } from "src/tables/table.resolver";
import { DataSourceService } from "../dataSources/dataSource.service";
import { DoltSystemTable } from "../systemTables/systemTable.enums";
import { listTablesQuery } from "../tables/table.queries";
import { ROW_LIMIT } from "../utils";
import { RefArgs } from "../utils/commonTypes";
Expand Down Expand Up @@ -40,43 +38,4 @@ export class RowResolver {
args.refName,
);
}

@Query(_returns => RowList)
async doltSchemas(
@Args() args: RefArgs,
type?: string,
): Promise<RowList | undefined> {
return this.dss.queryMaybeDolt(
async query => {
const tableName = DoltSystemTable.SCHEMAS;
const columns = await query(listTablesQuery, [tableName]);

const page = { columns, offset: 0 };
const { q, cols } = getRowsQuery(columns, !!type);

const params = [...cols, ROW_LIMIT + 1, page.offset];
const rows = await query(
q,
type ? [tableName, type, ...params] : [tableName, ...params],
);
return fromDoltListRowRes(rows, page.offset);
},
args.databaseName,
args.refName,
);
}

@Query(_returns => RowList)
async views(@Args() args: RefArgs): Promise<RowList | undefined> {
return this.doltSchemas(args, "view");
}

@Query(_returns => RowList, { nullable: true })
async doltProcedures(@Args() args: RefArgs): Promise<RowList | undefined> {
const tableArgs = {
...args,
tableName: DoltSystemTable.PROCEDURES,
};
return handleTableNotFound(async () => this.rows(tableArgs));
}
}
11 changes: 11 additions & 0 deletions packages/graphql-server/src/schemas/schema.enums.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { registerEnumType } from "@nestjs/graphql";

export enum SchemaType {
View,
Procedure,
Event,
Trigger,
Table,
}

registerEnumType(SchemaType, { name: "SchemaType" });
11 changes: 11 additions & 0 deletions packages/graphql-server/src/schemas/schema.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Field, ObjectType } from "@nestjs/graphql";
import { SchemaType } from "./schema.enums";

@ObjectType()
export class SchemaItem {
@Field()
name: string;

@Field(_type => SchemaType)
type: SchemaType;
}
18 changes: 18 additions & 0 deletions packages/graphql-server/src/schemas/schema.queries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { DoltSystemTable } from "../systemTables/systemTable.enums";

export const getDoltSchemasQuery = (hasWhereCause = false): string =>
`SELECT * FROM ${DoltSystemTable.SCHEMAS}${
hasWhereCause ? " WHERE type = ?" : ""
}`;

export const doltProceduresQuery = `SELECT * FROM ${DoltSystemTable.PROCEDURES}`;

export const getViewsQuery = `SELECT TABLE_SCHEMA, TABLE_NAME
FROM information_schema.tables
WHERE TABLE_TYPE = 'VIEW' AND TABLE_SCHEMA = ?`;

export const getTriggersQuery = `SHOW TRIGGERS`;

export const getEventsQuery = `SHOW EVENTS`;

export const getProceduresQuery = `SHOW PROCEDURE STATUS WHERE type = "PROCEDURE" AND db = ?`;
98 changes: 98 additions & 0 deletions packages/graphql-server/src/schemas/schema.resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { Args, Query, Resolver } from "@nestjs/graphql";
import { DataSourceService, ParQuery } from "../dataSources/dataSource.service";
import { handleTableNotFound } from "../tables/table.resolver";
import { RefArgs } from "../utils/commonTypes";
import { SchemaType } from "./schema.enums";
import { SchemaItem } from "./schema.model";
import {
doltProceduresQuery,
getDoltSchemasQuery,
getEventsQuery,
getProceduresQuery,
getTriggersQuery,
getViewsQuery,
} from "./schema.queries";

@Resolver(_of => SchemaItem)
export class SchemaResolver {
constructor(private readonly dss: DataSourceService) {}

@Query(_returns => [SchemaItem])
async doltSchemas(
@Args() args: RefArgs,
type?: SchemaType,
): Promise<SchemaItem[]> {
return this.dss.queryMaybeDolt(
async (query, isDolt) => {
if (!isDolt) {
return getSchemasForNonDolt(query, args.databaseName, type);
}

const res = await handleTableNotFound(async () =>
query(getDoltSchemasQuery(!!type), [type]),
);
if (!res) return [];
return res.map(r => {
return { name: r.name, type: r.type };
});
},
args.databaseName,
args.refName,
);
}

@Query(_returns => [SchemaItem])
async views(@Args() args: RefArgs): Promise<SchemaItem[]> {
return this.doltSchemas(args, SchemaType.View);
}

@Query(_returns => [SchemaItem])
async doltProcedures(@Args() args: RefArgs): Promise<[SchemaItem]> {
return this.dss.queryMaybeDolt(
async (query, isDolt) => {
if (!isDolt) {
const res = await query(getProceduresQuery, [args.databaseName]);
return res.map(r => {
return { name: r.Name, type: SchemaType.Procedure };
});
}

const res = await handleTableNotFound(async () =>
query(doltProceduresQuery),
);
if (!res) return [];
return res.map(r => {
return { name: r.name, type: SchemaType.Procedure };
});
},
args.databaseName,
args.refName,
);
}
}

async function getSchemasForNonDolt(
query: ParQuery,
dbName: string,
type?: SchemaType,
): Promise<SchemaItem[]> {
const vRes = await query(getViewsQuery, [dbName]);
const views = vRes.map(v => {
return { name: v.TABLE_NAME, type: SchemaType.View };
});
if (type === SchemaType.View) {
return views;
}

const tRes = await query(getTriggersQuery);
const triggers = tRes.map(t => {
return { name: t.Trigger, type: SchemaType.Trigger };
});

const eRes = await query(getEventsQuery);
const events = eRes.map(e => {
return { name: e.Name, type: SchemaType.Event };
});

return [...views, ...triggers, ...events];
}
8 changes: 3 additions & 5 deletions packages/web/components/CellButtons/HistoryButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useSqlEditorContext } from "@contexts/sqleditor";
import {
ColumnForDataTableFragment,
RowForDataTableFragment,
SchemaItemFragment,
} from "@gen/graphql-types";
import { isDoltSystemTable } from "@lib/doltSystemTables";
import { TableParams } from "@lib/params";
Expand Down Expand Up @@ -117,12 +118,9 @@ export default function HistoryButton(props: Props): JSX.Element | null {
);
}

function getIsView(
tableName: string,
views?: RowForDataTableFragment[],
): boolean {
function getIsView(tableName: string, views?: SchemaItemFragment[]): boolean {
if (!views) return false;
return views.some(v => v.columnValues[1].displayValue === tableName);
return views.some(v => v.name === tableName);
}

function queryHasMultipleTables(q?: string): boolean {
Expand Down
27 changes: 8 additions & 19 deletions packages/web/components/DatabaseTableNav/NavLinks.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import Loader from "@components/Loader";
import SchemaList from "@components/SchemaList";
import TableList from "@components/TableList";
import { Tab, TabList, TabPanel } from "@components/Tabs";
import { TabsProvider } from "@components/Tabs/context";
import Views from "@components/Views";
import NotDoltWrapper from "@components/util/NotDoltWrapper";
import useIsDolt from "@hooks/useIsDolt";
import { OptionalRefParams } from "@lib/params";
import { useRouter } from "next/router";
import { ReactNode } from "react";
Expand All @@ -22,24 +19,18 @@ type Props = {
export default function NavLinks({ className, params }: Props) {
const router = useRouter();
const initialActiveIndex = getActiveIndexFromRouterQuery(router.query.active);
const { hideDoltFeature, loading } = useIsDolt();
const tabs = ["Tables", "Views", "Schemas"];

return (
<div data-cy="db-page-table-nav" className={className}>
<TabsProvider initialActiveIndex={initialActiveIndex}>
<Loader loaded={!loading}>
<TabList className={css.tabList}>
{tabs.map((tab, i) => {
if (hideDoltFeature && tab === "Views") return null;
return (
<Tab key={tab} data-cy={`tab-${tab.toLowerCase()}`} index={i}>
{tab}
</Tab>
);
})}
</TabList>
</Loader>
<TabList className={css.tabList}>
{tabs.map((tab, i) => (
<Tab key={tab} data-cy={`tab-${tab.toLowerCase()}`} index={i}>
{tab}
</Tab>
))}
</TabList>
<CustomTabPanel index={0}>
{params.refName ? (
<TableList
Expand All @@ -56,9 +47,7 @@ export default function NavLinks({ className, params }: Props) {
</CustomTabPanel>
<CustomTabPanel index={1}>
{params.refName ? (
<NotDoltWrapper showNotDoltMsg feature="Listing views">
<Views params={{ ...params, refName: params.refName }} />
</NotDoltWrapper>
<Views params={{ ...params, refName: params.refName }} />
) : (
<p className={css.empty} data-cy="db-views-empty">
No views to show
Expand Down
3 changes: 2 additions & 1 deletion packages/web/components/SchemaList/Item.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Btn from "@components/Btn";
import Link from "@components/links/Link";
import excerpt from "@lib/excerpt";
import { RefParams } from "@lib/params";
import { sqlQuery } from "@lib/urls";
import { RiBookOpenLine } from "@react-icons/all-files/ri/RiBookOpenLine";
Expand Down Expand Up @@ -27,7 +28,7 @@ export default function Item({ name, params, isActive, query }: Props) {
data-cy={`db-schemas-${name}-play`}
>
<Btn className={css.button}>
<span className={css.name}>{name}</span>
<span className={css.name}>{excerpt(name, 45)}</span>
<span className={isActive ? css.viewing : css.icon}>
{isActive ? "Viewing" : <RiBookOpenLine />}
</span>
Expand Down
7 changes: 4 additions & 3 deletions packages/web/components/SchemaList/List.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import SmallLoader from "@components/SmallLoader";
import { SchemaType } from "@gen/graphql-types";
import { RefParams } from "@lib/params";
import { pluralize } from "@lib/pluralize";
import { useEffect } from "react";
import Item from "./Item";
import NotFound from "./NotFound";
import css from "./index.module.css";
import { SchemaKind, getActiveItem } from "./utils";
import { getActiveItem } from "./utils";

type InnerProps = {
params: RefParams & { q?: string };
items: string[];
kind: SchemaKind;
kind: SchemaType;
loading?: boolean;
};

export default function List(props: InnerProps) {
const activeItem = getActiveItem(props.kind, props.params.q);
const pluralKind = pluralize(2, props.kind);
const pluralKind = pluralize(2, props.kind.toLowerCase());

useEffect(() => {
if (!activeItem) return;
Expand Down
Loading
Loading