feat(d1): add Cloudflare D1 database support
This commit is contained in:
1 parent
977e7f78ca
commit
2a92746dc0
61 files changed
+1732
-69
No files matched your search
@@ -0,0 +1,33 @@
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import PasswordInput from "@/components/ui/PasswordInput.vue";
|
||||
|
||||
const accountId = defineModel<string>("accountId", { required: true });
|
||||
const databaseId = defineModel<string | undefined>("databaseId");
|
||||
const apiToken = defineModel<string>("apiToken", { required: true });
|
||||
const { t } = useI18n();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label class="justify-self-start text-left">{{ t("connection.d1AccountId") }}</Label>
|
||||
<Input v-model="accountId" class="col-span-3" placeholder="023e105f4ecef8ad9ca31a8372d0c353" />
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label class="justify-self-start text-left">{{ t("connection.d1DatabaseId") }}</Label>
|
||||
<Input v-model="databaseId" class="col-span-3" placeholder="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" />
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label class="justify-self-start text-left">{{ t("connection.d1ApiToken") }}</Label>
|
||||
<PasswordInput v-model="apiToken" class="col-span-3" placeholder="Cloudflare API Token" />
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-4 items-start gap-4">
|
||||
<span />
|
||||
<p class="col-span-3 text-xs text-muted-foreground">{{ t("connection.d1TokenHint") }}</p>
|
||||
</div>
|
||||
</template>
|
||||
@@ -50,9 +50,11 @@ import { buildDraftVisibleDatabasesConnectionId, connectionCanChooseVisibleDatab
|
||||
import { canSaveVisibleDatabaseSelection, connectionUsesVisibleSchemaFilter, filterDatabaseNamesForVisiblePicker, isSystemDatabaseName, normalizeVisibleDatabaseSelection, buildDraftVisibleSchemasConnectionId, normalizeVisibleSchemaSelection } from "@/lib/database/visibleDatabases";
|
||||
import { isSchemaAware, isSingleDatabase } from "@/lib/database/databaseFeatureSupport";
|
||||
import VisibleSchemasDialog from "@/components/sidebar/VisibleSchemasDialog.vue";
|
||||
import CloudflareD1ConnectionFields from "@/components/connection/CloudflareD1ConnectionFields.vue";
|
||||
import { oceanbaseModeConnectionPatch, oceanbaseSubModeFromConfig } from "@/lib/database/oceanbaseConnectionMode";
|
||||
import { translateBackendError } from "@/i18n/backend-errors";
|
||||
import { applyHiveKerberosSubmitConfig, hiveKerberosFormConfig, type HiveKerberosAuthMode } from "@/lib/database/hiveKerberosOptions";
|
||||
import { hasCloudflareD1Credentials, isCloudflareD1Connection, normalizeCloudflareD1Connection } from "@/lib/connection/cloudflareD1";
|
||||
|
||||
type DbOption = { value: string; label: string };
|
||||
type DbCategory = { key: string; title: string; options: DbOption[] };
|
||||
@@ -547,6 +549,7 @@ const driverProfiles: Record<
|
||||
sqlite: { type: "sqlite", port: 0, user: "", label: "SQLite", icon: "sqlite" },
|
||||
rqlite: { type: "rqlite", port: 4001, user: "", label: "RQLite", icon: "rqlite" },
|
||||
turso: { type: "turso", port: 443, user: "", label: "Turso", icon: "turso" },
|
||||
"cloudflare-d1": { type: "cloudflare-d1", port: 443, user: "", label: "Cloudflare D1", icon: "cloudflare-d1" },
|
||||
duckdb: { type: "duckdb", port: 0, user: "", label: "DuckDB", icon: "duckdb" },
|
||||
access: { type: "access", port: 0, user: "", label: "Microsoft Access", icon: "access" },
|
||||
mongodb: { type: "mongodb", port: 27017, user: "", label: "MongoDB", icon: "mongodb" },
|
||||
@@ -1635,6 +1638,7 @@ const iconTypeMap: Record<string, string> = {
|
||||
sqlite: "sqlite",
|
||||
rqlite: "rqlite",
|
||||
turso: "turso",
|
||||
"cloudflare-d1": "cloudflare-d1",
|
||||
access: "access",
|
||||
redis: "redis",
|
||||
mongodb: "mongodb",
|
||||
@@ -1724,6 +1728,7 @@ const dbOptions: DbOption[] = [
|
||||
{ value: "dm", label: "DM (Dameng)" },
|
||||
{ value: "opengauss", label: "openGauss" },
|
||||
{ value: "turso", label: "Turso" },
|
||||
{ value: "cloudflare-d1", label: "Cloudflare D1" },
|
||||
{ value: "duckdb", label: "DuckDB" },
|
||||
{ value: "rqlite", label: "RQLite" },
|
||||
{ value: "access", label: "Microsoft Access" },
|
||||
@@ -1915,7 +1920,7 @@ const zookeeperConnectString = computed({
|
||||
form.value.connection_string = normalizeZooKeeperConnectString(value);
|
||||
},
|
||||
});
|
||||
const canUseTransportLayers = computed(() => form.value.db_type !== "sqlite" && form.value.db_type !== "access" && !isH2FileMode.value);
|
||||
const canUseTransportLayers = computed(() => form.value.db_type !== "sqlite" && form.value.db_type !== "access" && !isCloudflareD1Connection(form.value) && !isH2FileMode.value);
|
||||
const shouldShowAgentDriverInstallHint = computed(() => showAgentDriverInstallHint(form.value.db_type, agentDrivers.value, form.value.driver_profile));
|
||||
const h2DriverMissing = computed(() => form.value.db_type === "h2" && isH2FileMode.value && agentDrivers.value.find((d) => d.db_type === "h2")?.installed !== true);
|
||||
const canChooseVisibleDatabases = computed(() => connectionCanChooseVisibleDatabases(form.value));
|
||||
@@ -2040,6 +2045,7 @@ const hasRequiredConnectionTarget = computed(() => {
|
||||
}
|
||||
if (form.value.db_type === "zookeeper") return !!(form.value.host || form.value.connection_string || connectionUrlInput.value.trim());
|
||||
if (form.value.db_type === "nacos") return !!nacosServerAddr.value.trim();
|
||||
if (isCloudflareD1Connection(form.value)) return hasCloudflareD1Credentials(form.value);
|
||||
if (isH2FileMode.value) return !!(form.value.host.trim() || h2FilePathFromJdbcUrl(form.value.connection_string));
|
||||
return !!(form.value.host || (mongoUseUrl.value && form.value.connection_string) || (form.value.db_type === "jdbc" && form.value.connection_string) || connectionUrlInput.value.trim());
|
||||
});
|
||||
@@ -2290,6 +2296,12 @@ function connectionConfigForSubmit(id: string): ConnectionConfig {
|
||||
throw new Error(t("connection.kingbaseDatabaseRequired"));
|
||||
}
|
||||
}
|
||||
if (isCloudflareD1Connection(config)) {
|
||||
normalizeCloudflareD1Connection(config);
|
||||
if (!hasCloudflareD1Credentials(config)) {
|
||||
throw new Error(t("connection.d1FieldsRequired"));
|
||||
}
|
||||
}
|
||||
config.transport_layers = (config.transport_layers || []).map(normalizeTransportLayer);
|
||||
config.transport_layers = config.transport_layers.map((layer) => {
|
||||
if (layer.type !== "ssh") return layer;
|
||||
@@ -4744,6 +4756,10 @@ function openExternalUrl(url: string) {
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-else-if="form.db_type === 'cloudflare-d1'">
|
||||
<CloudflareD1ConnectionFields v-model:account-id="form.host" v-model:database-id="form.database" v-model:api-token="form.password" />
|
||||
</template>
|
||||
|
||||
<!-- MySQL / PostgreSQL: host, port, user, password, database -->
|
||||
<template v-else>
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
|
||||
@@ -14,6 +14,7 @@ const assetIcons: Record<string, string> = {
|
||||
sqlite: "sqlite",
|
||||
rqlite: "rqlite.png",
|
||||
turso: "turso.png",
|
||||
cloudflare_d1: "cloudflare-d1",
|
||||
redis: "redis",
|
||||
mongodb: "mongodb",
|
||||
mongodb_legacy: "mongodb",
|
||||
|
||||
@@ -474,6 +474,8 @@ function connectionTooltipScheme(config: Pick<ConnectionConfig, "db_type" | "ssl
|
||||
case "turso":
|
||||
case "mq":
|
||||
return config.ssl ? "https" : "http";
|
||||
case "cloudflare-d1":
|
||||
return "https";
|
||||
case "dameng":
|
||||
return "dm";
|
||||
default:
|
||||
@@ -4825,7 +4827,7 @@ function treeItemMenuItems(): ContextMenuItem[] {
|
||||
items.push({ label: t("contextMenu.newQuery"), action: newQuery, icon: TerminalSquare });
|
||||
const sqlHistoryMenu = savedSqlHistorySubmenu();
|
||||
if (sqlHistoryMenu) items.push(sqlHistoryMenu);
|
||||
if (node.type === "database") {
|
||||
if (node.type === "database" && currentDatabaseType() !== "cloudflare-d1") {
|
||||
if (!isNodeDefaultDatabase.value) {
|
||||
items.push({ label: t("contextMenu.setDefaultDatabase"), action: setNodeAsDefaultDatabase, icon: Database });
|
||||
} else {
|
||||
|
||||
Reference in new issue
Block a user