Skip to content

Commit 3c84fc2

Browse files
lovasoacursoragent
andauthored
Add new database driver creation instructions to the contributing.md file (#35)
* Add guide for implementing new database drivers Co-authored-by: contact <[email protected]> * Refactor: Improve database driver contribution guide Co-authored-by: contact <[email protected]> * Refactor CONTRIBUTING.md to improve clarity and structure Co-authored-by: contact <[email protected]> --------- Co-authored-by: Cursor Agent <[email protected]>
1 parent 2384840 commit 3c84fc2

File tree

1 file changed

+208
-0
lines changed

1 file changed

+208
-0
lines changed

CONTRIBUTING.md

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,214 @@ To start with, check out:
3737

3838
Additionally, it's always good to work on improving/adding examples and documentation.
3939

40+
## Adding Support for New Databases
41+
42+
Adding support for a new database to SQLx is a significant undertaking that requires implementing multiple traits and components. This guide provides a step-by-step approach to building a database driver progressively, with testing at each stage.
43+
44+
### Overview of SQLx Architecture
45+
46+
SQLx uses a trait-based architecture where each database implements a set of core traits:
47+
48+
- **[`Database`](sqlx-core/src/database.rs)**: The main trait that defines all associated types for a database. This is the central trait that ties everything together and must be implemented for your database struct.
49+
50+
- **[`Connection`](sqlx-core/src/connection.rs)**: Handles database connections and basic operations like connecting, closing, pinging, and transaction management. See examples: [PostgreSQL](sqlx-core/src/postgres/connection/mod.rs), [MySQL](sqlx-core/src/mysql/connection/mod.rs), [SQLite](sqlx-core/src/sqlite/connection/mod.rs).
51+
52+
- **[`Row`](sqlx-core/src/row.rs)**: Represents a single row from a query result, providing access to column data by index or name. Examples: [PgRow](sqlx-core/src/postgres/row.rs), [MySqlRow](sqlx-core/src/mysql/row.rs).
53+
54+
- **[`Column`](sqlx-core/src/column.rs)**: Provides metadata about columns (name, type, etc.). Examples: [PgColumn](sqlx-core/src/postgres/column.rs), [MySqlColumn](sqlx-core/src/mysql/column.rs).
55+
56+
- **[`Value`](sqlx-core/src/value.rs) and [`ValueRef`](sqlx-core/src/value.rs)**: Handle owned and borrowed values from the database. Examples: [PgValue](sqlx-core/src/postgres/value.rs), [MySqlValue](sqlx-core/src/mysql/value.rs).
57+
58+
- **[`TypeInfo`](sqlx-core/src/type_info.rs)**: Provides information about database types for the type system. Examples: [PgTypeInfo](sqlx-core/src/postgres/type_info.rs), [MySqlTypeInfo](sqlx-core/src/mysql/type_info.rs).
59+
60+
- **[`Arguments`](sqlx-core/src/arguments.rs)**: Handles query parameter binding and encoding. Examples: [PgArguments](sqlx-core/src/postgres/arguments.rs), [MySqlArguments](sqlx-core/src/mysql/arguments.rs).
61+
62+
- **[`Statement`](sqlx-core/src/statement.rs)**: Handles prepared statements and their metadata. Examples: [PgStatement](sqlx-core/src/postgres/statement.rs), [MySqlStatement](sqlx-core/src/mysql/statement.rs).
63+
64+
- **Query execution**: Implement [`Executor`](sqlx-core/src/executor.rs) for your connection type to handle query execution and result streaming.
65+
66+
### Prerequisites
67+
68+
Before starting, ensure you have:
69+
1. A working database server/client library to connect to your database
70+
2. Understanding of your database's wire protocol or client API
71+
3. Knowledge of your database's type system and SQL dialect
72+
73+
### Step 1: Initial Setup and Feature Configuration
74+
75+
**1.1 Add feature flags to Cargo.toml files:**
76+
77+
Add your database feature to the main `Cargo.toml`, `sqlx-core/Cargo.toml`, and `sqlx-macros/Cargo.toml`. Follow the pattern used by existing databases like `postgres` or `mysql`. Include any native client library dependencies as optional dependencies.
78+
79+
**1.2 Create the basic module structure:**
80+
```bash
81+
mkdir -p sqlx-core/src/yourdb
82+
```
83+
84+
**1.3 Add the module to `sqlx-core/src/lib.rs` and main `src/lib.rs`** with appropriate feature gates.
85+
86+
**Test:** `cargo check --features yourdb`
87+
88+
### Step 2: Database Struct and Core Types
89+
90+
**2.1 Create your database struct** that will implement the [`Database`](sqlx-core/src/database.rs) trait. Look at [Postgres](sqlx-core/src/postgres/database.rs), [MySQL](sqlx-core/src/mysql/database.rs), or [SQLite](sqlx-core/src/sqlite/database.rs) for examples.
91+
92+
**2.2 Implement core types:**
93+
- **TypeInfo**: Represents your database's type system. Study existing implementations to understand how to map database types to Rust types.
94+
- **Value and ValueRef**: Handle data storage and retrieval. These work with your database's binary or text protocol.
95+
- **DatabaseError**: Convert your database's native errors to SQLx's error system.
96+
97+
**Test:** `cargo check --features yourdb`
98+
99+
### Step 3: Connection Implementation
100+
101+
**3.1 Implement [`Connection`](sqlx-core/src/connection.rs)** for your database. This handles:
102+
- Connection establishment and URL parsing ([`ConnectOptions`](sqlx-core/src/connection.rs))
103+
- Connection lifecycle (open, close, ping)
104+
- Basic connection management
105+
106+
Study the connection implementations in existing drivers, particularly how they handle:
107+
- Network protocols (see [PostgreSQL stream handling](sqlx-core/src/postgres/connection/stream.rs))
108+
- Authentication (see [MySQL auth](sqlx-core/src/mysql/connection/auth.rs))
109+
- Connection options parsing (see [PostgreSQL options](sqlx-core/src/postgres/options/mod.rs))
110+
111+
**Test:** Basic connection establishment
112+
113+
### Step 4: Type System Integration
114+
115+
**4.1 Implement [`Type`](sqlx-core/src/types/mod.rs), [`Encode`](sqlx-core/src/encode.rs), and [`Decode`](sqlx-core/src/decode.rs)** traits for basic Rust types.
116+
117+
Start with simple types like strings and integers. Look at existing type implementations:
118+
- [PostgreSQL types](sqlx-core/src/postgres/types/)
119+
- [MySQL types](sqlx-core/src/mysql/types/)
120+
- [SQLite types](sqlx-core/src/sqlite/types/)
121+
122+
Each type needs:
123+
- `Type` implementation to provide type metadata
124+
- `Encode` implementation to convert Rust values to database format
125+
- `Decode` implementation to convert database values to Rust types
126+
127+
**Test:** Type conversion unit tests
128+
129+
### Step 5: Query Arguments
130+
131+
**5.1 Implement [`Arguments`](sqlx-core/src/arguments.rs)** for your database. This handles parameter binding in prepared statements.
132+
133+
Study how existing databases handle parameter encoding:
134+
- [PostgreSQL arguments](sqlx-core/src/postgres/arguments.rs) (binary protocol)
135+
- [MySQL arguments](sqlx-core/src/mysql/arguments.rs) (binary protocol)
136+
- [SQLite arguments](sqlx-core/src/sqlite/arguments.rs) (uses native SQLite binding)
137+
138+
**Test:** Parameter binding and encoding
139+
140+
### Step 6: Query Execution
141+
142+
**6.1 Implement [`Executor`](sqlx-core/src/executor.rs)** for your connection type. This is where queries are actually sent to the database and results are processed.
143+
144+
Look at executor implementations:
145+
- [PostgreSQL executor](sqlx-core/src/postgres/connection/executor.rs)
146+
- [MySQL executor](sqlx-core/src/mysql/connection/executor.rs)
147+
- [SQLite executor](sqlx-core/src/sqlite/connection/executor.rs)
148+
149+
**6.2 Implement Row, Column, and QueryResult types** to handle query results and metadata.
150+
151+
**Test:** Basic query execution (`SELECT 1`, simple queries)
152+
153+
### Step 7: Statement Preparation
154+
155+
**7.1 Implement [`Statement`](sqlx-core/src/statement.rs)** if your database supports prepared statements.
156+
157+
Study existing statement implementations to understand:
158+
- Statement preparation and caching
159+
- Parameter metadata
160+
- Column metadata
161+
162+
**Test:** Prepared statement execution with parameters
163+
164+
### Step 8: Transaction Management
165+
166+
**8.1 Implement transaction support** by implementing the transaction-related methods in your `Connection` and creating a `TransactionManager`.
167+
168+
Look at existing transaction implementations:
169+
- [PostgreSQL transactions](sqlx-core/src/postgres/transaction.rs)
170+
- [MySQL transactions](sqlx-core/src/mysql/transaction.rs)
171+
172+
**Test:** BEGIN, COMMIT, ROLLBACK operations
173+
174+
### Step 9: Integration with Any Driver
175+
176+
**9.1 Add your database to the [`Any`](sqlx-core/src/any/) driver** to support runtime database selection.
177+
178+
This involves:
179+
- Adding your database to [`AnyKind`](sqlx-core/src/any/kind.rs)
180+
- Adding connection type to [`AnyConnectionKind`](sqlx-core/src/any/connection/mod.rs)
181+
- Updating delegation macros in Any implementations
182+
- Adding to other Any components (arguments, values, etc.)
183+
184+
Study how existing databases are integrated into the Any driver.
185+
186+
**Test:** Runtime database selection with Any driver
187+
188+
### Step 10: CI and Testing Infrastructure
189+
190+
**10.1 Add CI support** by updating `.github/workflows/ci.yml` with:
191+
- Your database service in GitHub Actions
192+
- Test job for your database
193+
- Appropriate environment variables and health checks
194+
195+
**10.2 Create integration tests** in `tests/yourdb/` following the pattern of existing database tests.
196+
197+
**10.3 Add testing utilities** by implementing [`TestSupport`](sqlx-core/src/testing/mod.rs) for your database.
198+
199+
### Step 11: Advanced Features (Optional)
200+
201+
**11.1 Migration support**: Implement [`MigrateDatabase`](sqlx-core/src/migrate/migrate.rs) if your database supports schema migrations.
202+
203+
**11.2 Listen/Notify**: If your database supports real-time notifications, implement listener functionality (see [PostgreSQL listener](sqlx-core/src/postgres/listener.rs)).
204+
205+
**11.3 Additional type support**: Add support for database-specific types, arrays, JSON, etc.
206+
207+
### Step 12: Documentation and Examples
208+
209+
**12.1 Add comprehensive documentation** to all public APIs with examples.
210+
211+
**12.2 Create examples** in `examples/yourdb/` showing common usage patterns.
212+
213+
**12.3 Update the main README** to include your database in the supported databases list.
214+
215+
### Testing Strategy
216+
217+
At each step, create tests that verify:
218+
219+
1. **Compilation**: `cargo check --features yourdb`
220+
2. **Unit tests**: Test individual components in isolation
221+
3. **Integration tests**: Test database connectivity and operations
222+
4. **Type safety**: Ensure compile-time type checking works
223+
5. **Runtime behavior**: Test actual database operations
224+
225+
### Implementation Tips
226+
227+
- **Study existing implementations**: The PostgreSQL, MySQL, and SQLite drivers provide excellent examples of different approaches (network protocols vs embedded databases, binary vs text protocols, etc.).
228+
229+
- **Start simple**: Begin with basic string queries before adding prepared statements, transactions, and complex types.
230+
231+
- **Incremental development**: Test each component thoroughly before moving to the next.
232+
233+
- **Protocol efficiency**: Use binary protocols when available for better performance.
234+
235+
- **Error handling**: Provide clear error messages and proper error type conversions.
236+
237+
- **Memory safety**: Pay careful attention to lifetimes, especially in async contexts.
238+
239+
### Common Patterns
240+
241+
- **Module organization**: Follow the established pattern of separate modules for connection, types, arguments, etc.
242+
- **Feature gating**: Ensure all database-specific code is behind feature flags.
243+
- **Async patterns**: Use `BoxFuture` for async trait methods and `BoxStream` for result streaming.
244+
- **Protocol handling**: Implement proper buffering and message framing for network protocols.
245+
246+
This progressive approach ensures you can test and validate each component before moving to the next, making the development process manageable and reducing the likelihood of errors.
247+
40248
## Communication
41249

42250
If you're unsure about your contribution or simply want to ask a question about anything, you can:

0 commit comments

Comments
 (0)