import type { ConnectionConfig, DatabaseType, TreeNodeType } from "@/types/database"; import { isMongoLegacyDriverProfile } from "@/lib/mongo/mongoCapabilities"; import { connectionIsEffectivelyReadOnly } from "@/lib/database/readOnlyWriteAccess"; export type DatabaseNamespaceCreationTarget = "database" | "schema" | "attach" | "special"; type ConnectionCreationTarget = Extract; type DatabaseNodeCreationTarget = Extract; export interface DatabaseNamespaceCreationMatrixEntry { connection?: ConnectionCreationTarget; database?: DatabaseNodeCreationTarget; deferred?: string; } type CreationConnection = (Pick & Partial>) | undefined; // Keep creation target-specific: many products expose schemas, files, or provider-managed namespaces instead of a top-level database. export const DATABASE_NAMESPACE_CREATION_MATRIX = { mysql: { connection: "database" }, postgres: { connection: "database", database: "schema" }, sqlite: { connection: "attach" }, rqlite: { deferred: "single SQLite-compatible database per node" }, turso: { deferred: "remote libSQL database lifecycle is provider-managed" }, "cloudflare-d1": { deferred: "Cloudflare D1 database lifecycle is provider-managed" }, redis: { deferred: "numbered logical databases are server-configured" }, duckdb: { connection: "attach" }, clickhouse: { connection: "database" }, sqlserver: { connection: "database", database: "schema" }, mongodb: { connection: "special" }, dynamodb: { deferred: "table creation requires dedicated DynamoDB key and capacity options" }, oracle: { deferred: "Oracle schemas are users; database creation is not a normal connected DDL action" }, elasticsearch: { deferred: "index creation is not modeled as database creation" }, easysearch: { deferred: "index creation is not modeled as database creation" }, meilisearch: { deferred: "index creation is not modeled as database creation" }, hbase: { deferred: "namespace creation needs dedicated HBase namespace options" }, qdrant: { deferred: "collection creation is separate from database creation" }, milvus: { deferred: "collection/database lifecycle needs a dedicated vector workflow" }, weaviate: { deferred: "collection creation is separate from database creation" }, chromadb: { deferred: "collection creation is separate from database creation" }, doris: { connection: "database" }, starrocks: { connection: "database" }, manticoresearch: { deferred: "index/table creation is not database creation" }, databend: { connection: "database" }, redshift: { connection: "database", database: "schema" }, dameng: { connection: "schema" }, gaussdb: { connection: "database", database: "schema" }, kingbase: { connection: "database", database: "schema" }, highgo: { connection: "database", database: "schema" }, uxdb: { database: "schema" }, vastbase: { connection: "database", database: "schema" }, goldendb: { connection: "database" }, kwdb: { connection: "database", database: "schema" }, yashandb: { connection: "database", database: "schema" }, databricks: { database: "schema" }, saphana: { database: "schema" }, teradata: { database: "schema" }, vertica: { database: "schema" }, firebird: { deferred: "database files are created through connection provisioning" }, exasol: { database: "schema" }, opengauss: { connection: "database", database: "schema" }, "oceanbase-oracle": { deferred: "Oracle-mode schemas are users; use a dedicated user workflow" }, questdb: { deferred: "single database model in DBX" }, gbase: { database: "schema" }, access: { deferred: "file-backed; create a new connection/file instead" }, h2: { database: "schema" }, snowflake: { connection: "database", database: "schema" }, trino: { database: "schema" }, prestosql: { database: "schema" }, hive: { deferred: "Hive database creation needs agent metadata validation first" }, argo: { deferred: "ArgoDB database creation needs agent metadata validation first" }, kyuubi: { deferred: "Kyuubi database creation needs dedicated metadata validation first" }, impala: { deferred: "Impala database creation needs dedicated metadata validation first" }, spark: { deferred: "Spark database creation needs agent metadata validation first" }, db2: { database: "schema" }, informix: { connection: "database" }, neo4j: { deferred: "database creation depends on edition/admin privileges" }, cassandra: { deferred: "keyspace creation requires replication options" }, bigquery: { deferred: "dataset creation needs project/location options" }, spanner: { deferred: "database creation requires the Cloud Spanner Admin API" }, kylin: { deferred: "project/model lifecycle is not SQL database creation" }, ignite: { deferred: "schema lifecycle is managed through cluster/cache configuration" }, ignite3: { deferred: "schema lifecycle is managed through cluster configuration" }, sundb: { deferred: "creation semantics not verified for first pass" }, oscar: { database: "schema" }, tdengine: { connection: "database" }, xugu: { database: "schema" }, iotdb: { deferred: "storage group/database semantics need dedicated IoTDB handling" }, etcd: { deferred: "key-value namespaces are not databases" }, zookeeper: { deferred: "key-value namespaces are not databases" }, iris: { database: "schema" }, influxdb: { connection: "database" }, influxdb3: { deferred: "database creation on InfluxDB 3.x goes through the /api/v3/configure/database admin endpoint, which is not part of the SQL execution path" }, victoriametrics: { deferred: "metric namespaces are managed by VictoriaMetrics deployment configuration" }, jdbc: { deferred: "generic JDBC does not expose a reliable dialect-specific create target" }, plugin: { deferred: "plugin-owned namespaces are managed by the provider workbench" }, mq: { deferred: "message queue namespaces are handled by MQ admin panels" }, nacos: { deferred: "Nacos namespace creation already uses the Nacos admin flow" }, consul: { deferred: "Consul namespaces and partitions are connection scopes, not KV resources" }, mqtt: { deferred: "MQTT topics are managed via the MQTT console" }, } satisfies Record; function namespaceCreationMatrixEntry(connection: NonNullable): DatabaseNamespaceCreationMatrixEntry { // GBase 8s shares `db_type: "gbase"` with the MySQL-based GBase 8a but is Informix-derived: // it has no `CREATE SCHEMA ` (a schema is the table owner) yet does support // `CREATE DATABASE`. Route it to the Informix-family semantics instead of the shared `gbase` // entry, which is written for GBase 8a. if (connection.db_type === "gbase" && connection.driver_profile === "gbase8s") { return { connection: "database" }; } return DATABASE_NAMESPACE_CREATION_MATRIX[connection.db_type]; } export function connectionNamespaceCreationTarget(connection: CreationConnection): ConnectionCreationTarget | null { if (!connection || connectionIsEffectivelyReadOnly(connection)) return null; if (connection.db_type === "mongodb" && isMongoLegacyDriverProfile(connection.driver_profile)) return null; if (connection.db_type === "sqlite" && (connection.host?.trim().toLowerCase() === ":memory:" || Boolean(connection.password))) { return null; } const entry: DatabaseNamespaceCreationMatrixEntry = namespaceCreationMatrixEntry(connection); return entry.connection ?? null; } export function databaseNodeNamespaceCreationTarget(connection: CreationConnection, node: Pick<{ type: TreeNodeType; database?: string | null }, "type" | "database">): DatabaseNodeCreationTarget | null { if (!connection || connectionIsEffectivelyReadOnly(connection) || node.type !== "database" || !node.database) return null; const entry: DatabaseNamespaceCreationMatrixEntry = namespaceCreationMatrixEntry(connection); return entry.database ?? null; } export function canCreateConnectionNamespace(connection: CreationConnection): boolean { return connectionNamespaceCreationTarget(connection) !== null; } export function canCreateDatabaseNodeNamespace(connection: CreationConnection, node: Pick<{ type: TreeNodeType; database?: string | null }, "type" | "database">): boolean { return databaseNodeNamespaceCreationTarget(connection, node) !== null; }