Skip to content

Commit 093935b

Browse files
committed
feat: add Cloudflare D1 database driver plugin (#206)
1 parent 9c08063 commit 093935b

17 files changed

Lines changed: 2545 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111

12+
- Cloudflare D1 database support
1213
- Match highlighting in autocomplete suggestions (matched characters shown in bold)
1314
- Loading spinner in autocomplete popup while fetching column metadata
1415

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
//
2+
// CloudflareD1Plugin.swift
3+
// TablePro
4+
//
5+
6+
import Foundation
7+
import os
8+
import TableProPluginKit
9+
10+
final class CloudflareD1Plugin: NSObject, TableProPlugin, DriverPlugin {
11+
static let pluginName = "Cloudflare D1 Driver"
12+
static let pluginVersion = "1.0.0"
13+
static let pluginDescription = "Cloudflare D1 serverless SQLite-compatible database support via REST API"
14+
static let capabilities: [PluginCapability] = [.databaseDriver]
15+
16+
static let databaseTypeId = "Cloudflare D1"
17+
static let databaseDisplayName = "Cloudflare D1"
18+
static let iconName = "cloudflare-d1-icon"
19+
static let defaultPort = 0
20+
21+
// MARK: - UI/Capability Metadata
22+
23+
static let connectionMode: ConnectionMode = .apiOnly
24+
static let supportsSSH = false
25+
static let supportsSSL = false
26+
static let isDownloadable = true
27+
static let supportsImport = false
28+
static let supportsSchemaEditing = false
29+
static let databaseGroupingStrategy: GroupingStrategy = .flat
30+
static let brandColorHex = "#F6821F"
31+
static let urlSchemes: [String] = ["d1"]
32+
33+
static let explainVariants: [ExplainVariant] = [
34+
ExplainVariant(id: "plan", label: "Query Plan", sqlPrefix: "EXPLAIN QUERY PLAN")
35+
]
36+
37+
static let structureColumnFields: [StructureColumnField] = [.name, .type, .nullable, .defaultValue]
38+
39+
static let columnTypesByCategory: [String: [String]] = [
40+
"Integer": ["INTEGER", "INT", "TINYINT", "SMALLINT", "MEDIUMINT", "BIGINT"],
41+
"Float": ["REAL", "DOUBLE", "FLOAT", "NUMERIC", "DECIMAL"],
42+
"String": ["TEXT", "VARCHAR", "CHARACTER", "CHAR", "CLOB", "NVARCHAR", "NCHAR"],
43+
"Date": ["DATE", "TIME", "DATETIME", "TIMESTAMP"],
44+
"Binary": ["BLOB"],
45+
"Boolean": ["BOOLEAN"]
46+
]
47+
48+
static let sqlDialect: SQLDialectDescriptor? = SQLDialectDescriptor(
49+
identifierQuote: "\"",
50+
keywords: [
51+
"SELECT", "FROM", "WHERE", "JOIN", "INNER", "LEFT", "RIGHT", "OUTER", "CROSS",
52+
"ON", "AND", "OR", "NOT", "IN", "LIKE", "GLOB", "BETWEEN", "AS",
53+
"ORDER", "BY", "GROUP", "HAVING", "LIMIT", "OFFSET",
54+
"INSERT", "INTO", "VALUES", "UPDATE", "SET", "DELETE",
55+
"CREATE", "ALTER", "DROP", "TABLE", "INDEX", "VIEW", "TRIGGER",
56+
"PRIMARY", "KEY", "FOREIGN", "REFERENCES", "UNIQUE", "CONSTRAINT",
57+
"ADD", "COLUMN", "RENAME",
58+
"NULL", "IS", "ASC", "DESC", "DISTINCT", "ALL",
59+
"CASE", "WHEN", "THEN", "ELSE", "END", "COALESCE", "IFNULL", "NULLIF",
60+
"UNION", "INTERSECT", "EXCEPT",
61+
"AUTOINCREMENT", "WITHOUT", "ROWID", "PRAGMA",
62+
"REPLACE", "ABORT", "FAIL", "IGNORE", "ROLLBACK",
63+
"TEMP", "TEMPORARY", "VACUUM", "EXPLAIN", "QUERY", "PLAN"
64+
],
65+
functions: [
66+
"COUNT", "SUM", "AVG", "MAX", "MIN", "GROUP_CONCAT", "TOTAL",
67+
"LENGTH", "SUBSTR", "SUBSTRING", "LOWER", "UPPER", "TRIM", "LTRIM", "RTRIM",
68+
"REPLACE", "INSTR", "PRINTF",
69+
"DATE", "TIME", "DATETIME", "JULIANDAY", "STRFTIME",
70+
"ABS", "ROUND", "RANDOM",
71+
"CAST", "TYPEOF",
72+
"COALESCE", "IFNULL", "NULLIF", "HEX", "QUOTE"
73+
],
74+
dataTypes: [
75+
"INTEGER", "REAL", "TEXT", "BLOB", "NUMERIC",
76+
"INT", "TINYINT", "SMALLINT", "MEDIUMINT", "BIGINT",
77+
"UNSIGNED", "BIG", "INT2", "INT8",
78+
"CHARACTER", "VARCHAR", "VARYING", "NCHAR", "NATIVE",
79+
"NVARCHAR", "CLOB",
80+
"DOUBLE", "PRECISION", "FLOAT",
81+
"DECIMAL", "BOOLEAN", "DATE", "DATETIME"
82+
],
83+
tableOptions: [
84+
"WITHOUT ROWID", "STRICT"
85+
],
86+
regexSyntax: .unsupported,
87+
booleanLiteralStyle: .numeric,
88+
likeEscapeStyle: .explicit,
89+
paginationStyle: .limit
90+
)
91+
92+
static let additionalConnectionFields: [ConnectionField] = [
93+
ConnectionField(
94+
id: "cfAccountId",
95+
label: String(localized: "Account ID"),
96+
placeholder: "Cloudflare Account ID",
97+
required: true,
98+
section: .authentication
99+
)
100+
]
101+
102+
func createDriver(config: DriverConnectionConfig) -> any PluginDatabaseDriver {
103+
CloudflareD1PluginDriver(config: config)
104+
}
105+
}

0 commit comments

Comments
 (0)