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

deployment #172

Merged
merged 6 commits into from
Oct 5, 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
7 changes: 7 additions & 0 deletions src/app/(theme)/client/[[...driver]]/page-client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import ValtownDriver from "@/drivers/valtown-driver";

import MyStudio from "@/components/my-studio";
import CloudflareD1Driver from "@/drivers/cloudflare-d1-driver";
import StarbaseDriver from "@/drivers/starbase-driver";

export default function ClientPageBody() {
const driver = useMemo(() => {
Expand All @@ -27,7 +28,13 @@ export default function ClientPageBody() {
"x-account-id": config.username ?? "",
"x-database-id": config.database ?? "",
});
} else if (config.driver === "starbase") {
return new StarbaseDriver("/proxy/starbase", {
Authorization: "Bearer " + (config.token ?? ""),
"x-starbase-url": config.url ?? "",
});
}

return new TursoDriver(config.url, config.token as string, true);
}, []);

Expand Down
6 changes: 6 additions & 0 deletions src/app/(theme)/client/s/[[...driver]]/page-client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useMemo } from "react";
import MyStudio from "@/components/my-studio";
import IndexdbSavedDoc from "@/drivers/saved-doc/indexdb-saved-doc";
import CloudflareD1Driver from "@/drivers/cloudflare-d1-driver";
import StarbaseDriver from "@/drivers/starbase-driver";

export default function ClientPageBody() {
const params = useSearchParams();
Expand Down Expand Up @@ -35,6 +36,11 @@ export default function ClientPageBody() {
"x-account-id": conn.config.username ?? "",
"x-database-id": conn.config.database ?? "",
});
} else if (conn.driver === "starbase") {
return new StarbaseDriver("/proxy/starbase", {
Authorization: "Bearer " + (conn.config.token ?? ""),
"x-starbase-url": conn.config.url ?? "",
});
}

return new TursoDriver(conn.config.url, conn.config.token, true);
Expand Down
11 changes: 11 additions & 0 deletions src/app/(theme)/connect/driver-dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,17 @@ export default function DriverDropdown({
</div>
</DropdownMenuItem>

<DropdownMenuItem
onClick={() => {
onSelect("starbase");
}}
>
<div className="flex gap-4 px-2 items-center h-8">
<SQLiteIcon className="w-6 h-6" />
<div className="font-semibold">StarbaseDB</div>
</div>
</DropdownMenuItem>

<DropdownMenuSeparator />

<DropdownMenuItem
Expand Down
37 changes: 37 additions & 0 deletions src/app/(theme)/connect/saved-connection-storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,41 @@ export const DRIVER_DETAIL: Record<SupportedDriver, DriverDetail> =
},
],
},
starbase: {
name: "starbase",
displayName: "Starbase",
icon: SQLiteIcon,
disableRemote: true,
prefill: "",
fields: [
{
name: "url",
title: "Endpoint",
required: true,
type: "text",
secret: false,
invalidate: (url: string): null | string => {
const trimmedUrl = url.trim();
const valid =
trimmedUrl.startsWith("https://") ||
trimmedUrl.startsWith("http://");

if (!valid) {
return "Endpoint must start with https:// or http://";
}

return null;
},
},
{
name: "token",
title: "API Token",
required: true,
type: "text",
secret: true,
},
],
},
"cloudflare-d1": {
name: "cloudflare-d1",
displayName: "Cloudflare D1",
Expand Down Expand Up @@ -211,8 +246,10 @@ export type SupportedDriver =
| "turso"
| "rqlite"
| "valtown"
| "starbase"
| "cloudflare-d1"
| "sqlite-filehandler";

export type SavedConnectionStorage = "remote" | "local";
export type SavedConnectionLabel = "gray" | "red" | "yellow" | "green" | "blue";

Expand Down
62 changes: 62 additions & 0 deletions src/app/proxy/starbase/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { HttpStatus } from "@/constants/http-status";
import { headers } from "next/headers";
import { NextRequest, NextResponse } from "next/server";

export const runtime = "edge";

export async function POST(req: NextRequest) {
// Get the account id and database id from header
const endpoint = headers().get("x-starbase-url");

if (!endpoint) {
return NextResponse.json(
{
error: "Please provide account id or database id",
},
{ status: HttpStatus.BAD_REQUEST }
);
}

const authorizationHeader = headers().get("Authorization");
if (!authorizationHeader) {
return NextResponse.json(
{
error: "Please provide authorization header",
},
{ status: HttpStatus.BAD_REQUEST }
);
}

try {
const url = `${endpoint.replace(/\/$/, "")}/query/raw`;

const response: { errors: { message: string }[] } = await (
await fetch(url, {
method: "POST",
headers: {
Authorization: authorizationHeader,
"Content-Type": "application/json",
},
body: JSON.stringify(await req.json()),
})
).json();

if (response.errors && response.errors.length > 0) {
return NextResponse.json(
{
error: response.errors[0].message,
},
{ status: HttpStatus.INTERNAL_SERVER_ERROR }
);
}

return NextResponse.json(response);
} catch (e) {
return NextResponse.json(
{
error: (e as Error).message,
},
{ status: HttpStatus.BAD_REQUEST }
);
}
}
2 changes: 1 addition & 1 deletion src/components/gui/main-connection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ function MainConnectionContainer() {
*/
useLayoutEffect(() => {
console.info("Injecting message into window object");
window.internalPubSub = new InternalPubSub();
if (!window.internalPubSub) window.internalPubSub = new InternalPubSub();
}, [driver]);

useEffect(() => {
Expand Down
5 changes: 4 additions & 1 deletion src/components/gui/query-result.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ export default function QueryResult({
return { _tag: "EXPLAIN", value: result.result } as const;
}

const state = OptimizeTableState.createFromResult(result.result);
const state = OptimizeTableState.createFromResult(
databaseDriver,
result.result
);
state.setReadOnlyMode(true);
state.mismatchDetection = databaseDriver.getFlags().mismatchDetection;
return { _tag: "QUERY", value: state } as const;
Expand Down
12 changes: 7 additions & 5 deletions src/components/gui/table-optimized/OptimizeTableState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { selectArrayFromIndexList } from "@/components/lib/export-helper";
import { OptimizeTableHeaderProps } from ".";
import { LucideKey, LucideKeySquare, LucideSigma } from "lucide-react";
import {
BaseDriver,
DatabaseResultSet,
DatabaseTableSchema,
TableColumnDataType,
Expand Down Expand Up @@ -37,14 +38,19 @@ export default class OptimizeTableState {
protected changeLogs: Record<number, OptimizeTableRowValue> = {};

static createFromResult(
driver: BaseDriver,
dataResult: DatabaseResultSet,
schemaResult?: DatabaseTableSchema
) {
return new OptimizeTableState(
dataResult.headers.map((header) => {
const headerData = schemaResult
? schemaResult.columns.find((c) => c.name === header.name)
: undefined;

let initialSize = 150;
const headerName = header.name;
const dataType = header.type;
const dataType = header.type ?? driver.inferTypeFromHeader(headerData);

if (
dataType === TableColumnDataType.INTEGER ||
Expand All @@ -67,10 +73,6 @@ export default class OptimizeTableState {
initialSize = Math.max(150, Math.min(500, maxSize * 8));
}

const headerData = schemaResult
? schemaResult.columns.find((c) => c.name === header.name)
: undefined;

// --------------------------------------
// Matching foreign key
// --------------------------------------
Expand Down
1 change: 1 addition & 0 deletions src/components/gui/tabs/table-data-tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export default function TableDataWindow({
});

const tableState = OptimizeTableState.createFromResult(
databaseDriver,
dataResult,
schemaResult
);
Expand Down
2 changes: 1 addition & 1 deletion src/components/gui/toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export function ToolbarButton({
if (tooltip) {
return (
<Tooltip>
<TooltipTrigger>{buttonContent}</TooltipTrigger>
<TooltipTrigger asChild>{buttonContent}</TooltipTrigger>
<TooltipContent>{tooltip}</TooltipContent>
</Tooltip>
);
Expand Down
10 changes: 10 additions & 0 deletions src/drivers/base-driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,12 @@ export interface DriverFlags {
supportModifyColumn: boolean;
mismatchDetection: boolean;
dialect: SupportedDialect;

// If database supports this, we don't need
// to make a separate request to get updated
// data when update
supportInsertReturning: boolean;
supportUpdateReturning: boolean;
}

export interface DatabaseTableColumnChange {
Expand Down Expand Up @@ -252,6 +258,10 @@ export abstract class BaseDriver {
tableName: string
): Promise<DatabaseTableSchema>;

abstract inferTypeFromHeader(
header?: DatabaseTableColumn
): TableColumnDataType | undefined;

abstract trigger(
schemaName: string,
name: string
Expand Down
49 changes: 37 additions & 12 deletions src/drivers/common-sql-imp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,25 @@ export default abstract class CommonSQLImplement extends BaseDriver {

const sqls = ops.map((op) => {
if (op.operation === "INSERT")
return insertInto(this, schemaName, tableName, op.values);
return insertInto(
this,
schemaName,
tableName,
op.values,
this.getFlags().supportInsertReturning
);

if (op.operation === "DELETE")
return deleteFrom(this, schemaName, tableName, op.where);

return updateTable(this, schemaName, tableName, op.values, op.where);
return updateTable(
this,
schemaName,
tableName,
op.values,
op.where,
this.getFlags().supportInsertReturning
);
});

const result = await this.transaction(sqls);
Expand All @@ -57,18 +71,29 @@ export default abstract class CommonSQLImplement extends BaseDriver {
}

if (op.operation === "UPDATE") {
const selectResult = await this.findFirst(
schemaName,
tableName,
op.where
);
if (r.rows.length === 1)
// This is when database support RETURNING
tmp.push({
record: r.rows[0],
});
else {
const selectResult = await this.findFirst(
schemaName,
tableName,
op.where
);

tmp.push({
lastId: r.lastInsertRowid,
record: selectResult.rows[0],
});
tmp.push({
lastId: r.lastInsertRowid,
record: selectResult.rows[0],
});
}
} else if (op.operation === "INSERT") {
if (op.autoIncrementPkColumn) {
if (r.rows.length === 1) {
tmp.push({
record: r.rows[0],
});
} else if (op.autoIncrementPkColumn) {
const selectResult = await this.findFirst(schemaName, tableName, {
[op.autoIncrementPkColumn]: r.lastInsertRowid,
});
Expand Down
8 changes: 8 additions & 0 deletions src/drivers/mysql/mysql-driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
DriverFlags,
DatabaseSchemaItem,
DatabaseTableColumn,
TableColumnDataType,
} from "../base-driver";
import CommonSQLImplement from "../common-sql-imp";
import { escapeSqlValue } from "../sqlite/sql-helper";
Expand Down Expand Up @@ -53,6 +54,9 @@ export default abstract class MySQLLikeDriver extends CommonSQLImplement {
mismatchDetection: false,
supportCreateUpdateTable: false,
dialect: "mysql",

supportInsertReturning: false,
supportUpdateReturning: false,
};
}

Expand Down Expand Up @@ -153,4 +157,8 @@ export default abstract class MySQLLikeDriver extends CommonSQLImplement {
createUpdateTableSchema(): string[] {
throw new Error("Not implemented");
}

inferTypeFromHeader(): TableColumnDataType | undefined {
return undefined;
}
}
Loading
Loading