Skip to content

Commit

Permalink
web: Postgres sql builder tests
Browse files Browse the repository at this point in the history
  • Loading branch information
tbantle22 committed Dec 15, 2023
1 parent f04cba6 commit 4b6ddbe
Show file tree
Hide file tree
Showing 11 changed files with 548 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ export default function Item({ conn, onDeleteClicked }: Props) {
return;
}
const { href, as } =
conn.type === DatabaseType.Mysql
? maybeDatabase(db.data.addDatabaseConnection.currentDatabase)
: maybeSchema(db.data.addDatabaseConnection.currentSchema);
conn.type === DatabaseType.Postgres
? maybeSchema(db.data.addDatabaseConnection.currentSchema)
: maybeDatabase(db.data.addDatabaseConnection.currentDatabase);
router.push(href, as).catch(console.error);
} catch (_) {
// Handled by res.error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { FiUpload } from "@react-icons/all-files/fi/FiUpload";
import { ImTable2 } from "@react-icons/all-files/im/ImTable2";
import OptionSquare from "./OptionSquare";
import css from "./index.module.css";
import { mapColsToFakeValues } from "./utils";
import { mapColTypeToFakeValue } from "./utils";

type Props = {
params: TableParams;
Expand All @@ -34,7 +34,7 @@ export default function EditTableButtons(props: Props) {
const uploadParams = { ...props.params, uploadId: String(Date.now()) };

const onWriteQuery = () => {
const values = mapColsToFakeValues(columns);
const values = columns?.map(mapColTypeToFakeValue) ?? [];
const colNames = columns?.map(c => c.name) ?? [];
setEditorString(insertIntoTable(props.params.tableName, colNames, values));
toggleSqlEditor(true);
Expand Down
26 changes: 4 additions & 22 deletions web/components/pageComponents/DatabasePage/ForTable/utils.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,12 @@
import { ColumnForDataTableFragment } from "@gen/graphql-types";
import { escapeSingleQuotes } from "@hooks/useSqlBuilder/util";
import { ColumnValue } from "@hooks/useSqlBuilder/util";
import { getDateString, getTimeWithSeconds } from "@lib/dateConversions";
import { loremer } from "@lib/loremer";
import nTimes from "@lib/nTimes";

type ColValue = {
type: string;
value: any;
};

export function mapColsToFakeValues(
cols?: ColumnForDataTableFragment[],
): ColValue[] {
if (!cols) {
return [];
}
return cols.map(c => {
const v = mapColTypeToFakeValue(c);
if (v.type === "single_quote_string") {
return { type: v.type, value: escapeSingleQuotes(v.value) };
}
return v;
});
}

function mapColTypeToFakeValue(col: ColumnForDataTableFragment): ColValue {
export function mapColTypeToFakeValue(
col: ColumnForDataTableFragment,
): ColumnValue {
const lower = col.type.toLowerCase();
if (lower.includes("int")) {
return { type: "number", value: getFakeInt(col.type) };
Expand Down
28 changes: 21 additions & 7 deletions web/hooks/useSqlBuilder/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ColumnForDataTableFragment, SchemaType } from "@gen/graphql-types";
import useSqlParser from "@hooks/useSqlParser";
import { Alter, Delete, Insert_Replace, Select, Update } from "node-sql-parser";
import {
ColumnValue,
Conditions,
escapeSingleQuotes,
escapeSingleQuotesInWhereObj,
Expand Down Expand Up @@ -136,26 +137,39 @@ export default function useSqlBuilder() {
sel = parsed;
}
}
sel.where = getWhereFromPKCols(conditions, sel.where, isPostgres);
sel.where = getWhereFromPKCols(conditions, isPostgres, sel.where);
return convertToSqlSelect(sel);
}

function insertIntoTable(
tableName: string,
cols: string[],
vals: Array<{ type: string; value: any }>,
vals: Array<ColumnValue>,
): string {
return convertToSqlInsert({
table: [{ table: tableName }],
columns: cols,
values: [{ type: "expr_list", value: vals }],
values: [
{
type: "expr_list",
value: vals.map(v => {
if (v.type === "single_quote_string") {
return {
type: v.type,
value: escapeSingleQuotes(v.value, isPostgres),
};
}
return v;
}),
},
],
});
}

function deleteFromTable(tableName: string, cond: Conditions): string {
return convertToSqlDelete({
from: [{ table: tableName, db: null, as: null }],
where: getWhereFromPKCols(cond, null, isPostgres),
where: getWhereFromPKCols(cond, isPostgres),
});
}

Expand All @@ -178,7 +192,7 @@ where schemaname='${dbName}';`;
type: "function",
args: {
type: "expr_list",
value: [getWhereFromPKCols(conditions, null, isPostgres)],
value: [getWhereFromPKCols(conditions, isPostgres)],
},
},
});
Expand Down Expand Up @@ -211,7 +225,7 @@ where schemaname='${dbName}';`;
): string {
return convertToSqlUpdate({
table: [{ table: tableName, db: null, as: null }],
where: getWhereFromPKCols(conditions, null, isPostgres),
where: getWhereFromPKCols(conditions, isPostgres),
set: [
{
column: setCol,
Expand All @@ -232,7 +246,7 @@ where schemaname='${dbName}';`;
): string {
return convertToSqlUpdate({
table: [{ table: tableName, db: null, as: null }],
where: getWhereFromPKCols(conditions, null, isPostgres),
where: getWhereFromPKCols(conditions, isPostgres),
set: [
{ column: setCol, value: { type: "null", value: null }, table: null },
],
Expand Down
62 changes: 23 additions & 39 deletions web/hooks/useSqlBuilder/tests/mysql.test.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,14 @@
import { MockedProvider } from "@apollo/client/testing";
import { toPKCols } from "@components/CellButtons/queryHelpers";
import { databaseDetailsMock } from "@components/util/NotDoltWrapper/mocks";
import {
ColumnForDataTableFragment,
RowForDataTableFragment,
} from "@gen/graphql-types";
import { NULL_VALUE } from "@lib/null";
import { TableParams } from "@lib/params";
import { renderHook } from "@testing-library/react";
import { ReactNode } from "react";
import useSqlBuilder from "..";
import { Conditions } from "../util";
import { renderUseSqlBuilder } from "./render.test";
import * as td from "./testData";

function renderUseSqlBuilder(isPostgres = false) {
const wrapper = ({ children }: { children: ReactNode }) => (
<MockedProvider mocks={[databaseDetailsMock(true, true, isPostgres)]}>
{children}
</MockedProvider>
);

const { result } = renderHook(() => useSqlBuilder(), { wrapper });
return result.current;
}

describe("test addWhereClauseToSelect", () => {
const column = "rating";
const value = "10";
Expand Down Expand Up @@ -72,22 +57,22 @@ describe("test addWhereClauseToSelect", () => {
];

tests.forEach(test => {
it(test.desc, () => {
const { addWhereClauseToSelect } = renderUseSqlBuilder();
it(test.desc, async () => {
const { addWhereClauseToSelect } = await renderUseSqlBuilder();
expect(addWhereClauseToSelect(tableName, cond, test.q)).toBe(
test.expected,
);
});
it(`${test.desc}, null condition`, () => {
const { addWhereClauseToSelect } = renderUseSqlBuilder();
it(`${test.desc}, null condition`, async () => {
const { addWhereClauseToSelect } = await renderUseSqlBuilder();
expect(addWhereClauseToSelect(tableName, nullCond, test.q)).toBe(
test.expectedNull,
);
});
});

it("does not throw error", () => {
const { addWhereClauseToSelect } = renderUseSqlBuilder();
it("does not throw error", async () => {
const { addWhereClauseToSelect } = await renderUseSqlBuilder();
expect(() =>
addWhereClauseToSelect(tableName, cond, td.invalidQuery),
).not.toThrow();
Expand Down Expand Up @@ -163,8 +148,8 @@ describe("test addWhereClauseToSelect for cell buttons", () => {
];

tests.forEach(t => {
it(t.desc, () => {
const { addWhereClauseToSelect } = renderUseSqlBuilder();
it(t.desc, async () => {
const { addWhereClauseToSelect } = await renderUseSqlBuilder();
expect(
addWhereClauseToSelect(t.params.tableName, t.cols, t.params.q),
).toEqual(t.expectedQuery);
Expand Down Expand Up @@ -211,23 +196,23 @@ describe("test convertToSqlWithOrderBy", () => {
];

tests.forEach(test => {
it(`${test.desc}, add order by`, () => {
const { convertToSqlWithOrderBy } = renderUseSqlBuilder();
it(`${test.desc}, add order by`, async () => {
const { convertToSqlWithOrderBy } = await renderUseSqlBuilder();
expect(convertToSqlWithOrderBy(test.query, column, type)).toBe(
test.queryWithOrderBy,
);
});

it(`${test.desc}, remove order by`, () => {
const { convertToSqlWithOrderBy } = renderUseSqlBuilder();
it(`${test.desc}, remove order by`, async () => {
const { convertToSqlWithOrderBy } = await renderUseSqlBuilder();
expect(convertToSqlWithOrderBy(test.queryWithOrderBy, column)).toBe(
test.queryRemovedOrderBy ?? test.query,
);
});
});

it("does not throw error", () => {
const { convertToSqlWithOrderBy } = renderUseSqlBuilder();
it("does not throw error", async () => {
const { convertToSqlWithOrderBy } = await renderUseSqlBuilder();
expect(() =>
convertToSqlWithOrderBy(td.invalidQuery, column),
).not.toThrow();
Expand Down Expand Up @@ -289,16 +274,16 @@ describe("test removeColumnFromQuery", () => {
];

tests.forEach(test => {
it(test.desc, () => {
const { removeColumnFromQuery } = renderUseSqlBuilder();
it(test.desc, async () => {
const { removeColumnFromQuery } = await renderUseSqlBuilder();
expect(
removeColumnFromQuery(test.query, test.colToRemove, test.cols),
).toEqual(test.expected);
});
});

it("remove column doesn't throw error", () => {
const { removeColumnFromQuery } = renderUseSqlBuilder();
it("remove column doesn't throw error", async () => {
const { removeColumnFromQuery } = await renderUseSqlBuilder();
expect(() =>
removeColumnFromQuery(td.invalidQuery, "age", td.columns.slice(0, 2)),
).not.toThrow();
Expand Down Expand Up @@ -348,8 +333,8 @@ describe("test deleteFromTable", () => {
];

tests.forEach(t => {
it(t.desc, () => {
const { deleteFromTable } = renderUseSqlBuilder();
it(t.desc, async () => {
const { deleteFromTable } = await renderUseSqlBuilder();
expect(deleteFromTable(t.tableName, toPKCols(t.row, t.columns))).toEqual(
t.expectedQuery,
);
Expand Down Expand Up @@ -402,14 +387,13 @@ describe("test updateTableQuery", () => {
td.nameSingleQuoteColValue,
],
},
// TODO: Is this the right escaping?
expectedQuery: `UPDATE \`test-table\` SET \`name\` = 'New Name' WHERE \`id\` = '1' AND \`pk2\` = '2' AND \`name\` = 'Taylor\\'s chair'`,
},
];

tests.forEach(test => {
it(test.desc, () => {
const { updateTableQuery } = renderUseSqlBuilder();
it(test.desc, async () => {
const { updateTableQuery } = await renderUseSqlBuilder();
expect(
updateTableQuery(
test.tableName,
Expand Down
Loading

0 comments on commit 4b6ddbe

Please sign in to comment.