| Crates.io | xdl-database |
| lib.rs | xdl-database |
| version | 0.1.1 |
| created_at | 2025-12-31 19:34:49.110888+00 |
| updated_at | 2025-12-31 23:21:28.806033+00 |
| description | Database connectivity module for XDL - supports PostgreSQL, MySQL, DuckDB, SQLite, ODBC, Redis, and more |
| homepage | https://turingworks.github.io/xdl |
| repository | https://github.com/turingworks/xdl |
| max_upload_size | |
| id | 2015183 |
| size | 249,638 |
Unified database connectivity for XDL supporting multiple database systems including PostgreSQL, MySQL, DuckDB, ODBC, Redis, and Kafka.
Multiple Database Support
Async/Await Support - Built on Tokio for high-performance async operations
Connection Pooling - Efficient connection management (via deadpool)
Type-Safe Queries - Automatic type conversion to XDL types
Object-Oriented API - Familiar IDL/GDL-style object interface
Add to your Cargo.toml:
[dependencies]
xdl-database = { path = "../xdl-database", features = ["postgres-support", "duckdb-support", "redis-support"] }
postgres-support - PostgreSQL supportmysql-support - MySQL supportduckdb-support - DuckDB supportodbc-support - ODBC supportredis-support - Redis supportkafka-support - Apache Kafka supportall - Enable all databases; Create a database object
objdb = OBJ_NEW('XDLdbDatabase')
; Connect to PostgreSQL
conn_str = 'postgresql://user:password@localhost:5432/dbname'
objdb->Connect, CONNECTION=conn_str
; Execute a query
recordset = objdb->ExecuteSQL('SELECT * FROM my_table')
; Get the data
data = recordset->GetData()
PRINT, data
; Get row count
n_rows = recordset->RowCount()
PRINT, 'Number of rows:', n_rows
; Get column names
columns = recordset->ColumnNames()
PRINT, 'Columns:', columns
; Cleanup
recordset->Destroy()
objdb->Disconnect()
OBJ_DESTROY, objdb
; Create database object
objdb = OBJ_NEW('XDLdbDatabase')
; Connect to MySQL
objdb->Connect, CONNECTION='mysql://root:password@localhost:3306/testdb'
; Create a table
objdb->ExecuteCommand, 'CREATE TABLE employees (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100), salary DECIMAL(10,2))'
; Insert data
objdb->ExecuteCommand, "INSERT INTO employees (name, salary) VALUES ('Alice', 95000.00)"
objdb->ExecuteCommand, "INSERT INTO employees (name, salary) VALUES ('Bob', 75000.00)"
; Query data
recordset = objdb->ExecuteSQL('SELECT * FROM employees ORDER BY salary DESC')
data = recordset->GetData()
PRINT, data
; Cleanup
recordset->Destroy()
objdb->Disconnect()
OBJ_DESTROY, objdb
; Create database object
objdb = OBJ_NEW('XDLdbDatabase')
; Connect to DuckDB file
objdb->Connect, CONNECTION='my_data.duckdb'
; Create a table
objdb->ExecuteCommand, 'CREATE TABLE users (id INTEGER, name VARCHAR)'
; Insert data
objdb->ExecuteCommand, "INSERT INTO users VALUES (1, 'Alice'), (2, 'Bob')"
; Query data
recordset = objdb->ExecuteSQL('SELECT * FROM users WHERE id > 0')
data = recordset->GetData()
PRINT, data
; Cleanup
recordset->Destroy()
objdb->Disconnect()
OBJ_DESTROY, objdb
; Create database object
objdb = OBJ_NEW('XDLdbDatabase')
; Connect to Redis
objdb->Connect, CONNECTION='redis://localhost:6379'
; Set a value
objdb->ExecuteCommand, 'SET mykey myvalue'
; Delete a key
rows_affected = objdb->ExecuteCommand('DEL mykey')
PRINT, 'Rows affected:', rows_affected
; Cleanup
objdb->Disconnect()
OBJ_DESTROY, objdb
; Create database object
objdb = OBJ_NEW('XDLdbDatabase')
; Connect to SQL Server via ODBC
conn_str = 'DRIVER={ODBC Driver 17 for SQL Server};SERVER=localhost;DATABASE=mydb;UID=user;PWD=pass'
objdb->Connect, CONNECTION=conn_str
; Create table
objdb->ExecuteCommand, 'CREATE TABLE Products (ID INT, Name NVARCHAR(100), Price DECIMAL(10,2))'
; Insert data
objdb->ExecuteCommand, "INSERT INTO Products VALUES (1, 'Laptop', 1299.99)"
; Query data
recordset = objdb->ExecuteSQL('SELECT * FROM Products')
data = recordset->GetData()
PRINT, data
; Cleanup
recordset->Destroy()
objdb->Disconnect()
OBJ_DESTROY, objdb
; Create database object
objdb = OBJ_NEW('XDLdbDatabase')
; Connect to Kafka
objdb->Connect, CONNECTION='kafka://localhost:9092'
; Create a topic
objdb->ExecuteSQL, 'CREATE TOPIC my-topic'
; Produce messages
objdb->ExecuteSQL, 'PRODUCE TO my-topic: Hello from XDL!'
objdb->ExecuteSQL, 'PRODUCE TO my-topic: Second message'
; Consume messages
recordset = objdb->ExecuteSQL('CONSUME FROM my-topic LIMIT 10')
messages = recordset->GetData()
PRINT, messages
; List topics
topics = objdb->ExecuteSQL('LIST TOPICS')
PRINT, topics->GetData()
; Cleanup
recordset->Destroy()
topics->Destroy()
objdb->Disconnect()
OBJ_DESTROY, objdb
; Connect to PostgreSQL
objdb = OBJ_NEW('XDLdbDatabase')
objdb->Connect, CONNECTION='postgresql://localhost/mydb'
; Execute complex query
query = 'SELECT id, name, salary FROM employees WHERE department = ''Engineering'' ORDER BY salary DESC'
recordset = objdb->ExecuteSQL(query)
; Get data as structured columns
data_struct = recordset->GetDataStructured()
; Access individual columns
ids = data_struct.id
names = data_struct.name
salaries = data_struct.salary
; Print results
FOR i = 0, N_ELEMENTS(ids) - 1 DO BEGIN
PRINT, ids[i], names[i], salaries[i]
ENDFOR
; Cleanup
recordset->Destroy()
objdb->Disconnect()
OBJ_DESTROY, objdb
postgresql://user:password@host:port/database
postgres://user:password@host:port/database
mysql://user:password@host:port/database
mysql://user:password@host/database (port defaults to 3306)
mysql://root:pass@localhost:3306/mydb
Also compatible with MariaDB and other MySQL-protocol databases.
duckdb://path/to/file.duckdb
/path/to/file.duckdb
file.db
DRIVER={PostgreSQL Unicode(x64)};SERVER=host;UID=user;PWD=password;DATABASE=dbname;PORT=5432
redis://localhost:6379
redis://:password@localhost:6379/0
kafka://localhost:9092
kafka://broker1:9092,broker2:9092 (multiple brokers)
localhost:9092 (simplified format)
Special Kafka Query Syntax:
Kafka uses a special query syntax since it's a streaming platform:
; Topic Management
'LIST TOPICS'
'CREATE TOPIC topic-name'
'DELETE TOPIC topic-name'
; Producer (send messages)
'PRODUCE TO topic-name: message content'
'PRODUCE TO sensors: {"temp":25.5,"humidity":60}'
; Consumer (read messages)
'CONSUME FROM topic-name LIMIT 10'
'CONSUME FROM events LIMIT 100'
objdb->Connect, CONNECTION=connection_string
Connects to the database using the specified connection string.
objdb->Disconnect
Disconnects from the database.
recordset = objdb->ExecuteSQL(query_string)
Executes a SELECT query and returns a recordset object.
rows_affected = objdb->ExecuteCommand(command_string)
Executes a command (INSERT, UPDATE, DELETE) and returns the number of rows affected.
connected = objdb->IsConnected()
Returns 1 if connected, 0 otherwise.
db_type = objdb->DatabaseType()
Returns the type of database currently connected.
data = recordset->GetData()
Returns all data as a nested array.
data_struct = recordset->GetDataStructured()
Returns data as a structure with column names as fields.
column_data = recordset->GetColumn('column_name')
Returns a specific column as an array.
n_rows = recordset->RowCount()
Returns the number of rows in the recordset.
n_cols = recordset->ColumnCount()
Returns the number of columns in the recordset.
names = recordset->ColumnNames()
Returns an array of column names.
has_more = recordset->Next()
Moves to the next row. Returns 1 if successful, 0 if no more rows.
recordset->Reset
Resets the cursor to the first row.
row_data = recordset->CurrentRow()
Returns the current row as a structure.
xdl-database/
├── src/
│ ├── lib.rs # Main module, registry, XDLDatabase
│ ├── error.rs # Error types
│ ├── connection.rs # Connection enum wrapper
│ ├── recordset.rs # Query results
│ └── drivers/
│ ├── mod.rs # Driver exports
│ ├── postgres.rs # PostgreSQL driver
│ ├── mysql.rs # MySQL driver
│ ├── duckdb.rs # DuckDB driver
│ ├── odbc.rs # ODBC driver
│ ├── redis_driver.rs # Redis driver
│ └── kafka.rs # Kafka driver
├── Cargo.toml
└── README.md
XDLDatabase - Main database object
DatabaseConnection - Enum wrapper for different database types
Recordset - Query results container
DatabaseRegistry - Global object registry
Drivers - Individual database implementations
Database types are automatically converted to XDL types:
| Database Type | XDL Type |
|---|---|
| BOOLEAN | Long (0/1) |
| SMALLINT | Int |
| INTEGER | Long |
| BIGINT | Long64 |
| REAL/FLOAT4 | Float |
| DOUBLE/FLOAT8 | Double |
| VARCHAR/TEXT | String |
| NULL | Undefined |
The module provides comprehensive error handling:
objdb = OBJ_NEW('XDLdbDatabase')
; Try to connect
CATCH, error
IF error NE 0 THEN BEGIN
PRINT, 'Connection failed: ', !ERROR_STATE.MSG
RETURN
ENDIF
objdb->Connect, CONNECTION='postgresql://localhost/mydb'
; Execute query with error handling
CATCH, error
IF error NE 0 THEN BEGIN
PRINT, 'Query failed: ', !ERROR_STATE.MSG
objdb->Disconnect()
RETURN
ENDIF
recordset = objdb->ExecuteSQL('SELECT * FROM users')
; Prepared statement
stmt = objdb->Prepare('SELECT * FROM users WHERE id = ?')
recordset = stmt->Execute([123])
; Transaction
objdb->BeginTransaction()
objdb->ExecuteCommand('INSERT INTO users VALUES (1, ''Alice'')')
objdb->ExecuteCommand('INSERT INTO users VALUES (2, ''Bob'')')
objdb->Commit()
; Connection pool
pool = OBJ_NEW('XDLdbConnectionPool', SIZE=10)
pool->Connect, CONNECTION='postgresql://localhost/mydb'
conn1 = pool->GetConnection()
conn2 = pool->GetConnection()
Run tests with:
cargo test --package xdl-database --all-features
See the examples/ directory for more usage examples:
postgresql_example.xdl - PostgreSQL query examplemysql_example.xdl - MySQL CRUD operations and queriesduckdb_analytics.xdl - DuckDB analytics exampleodbc_sqlserver_example.xdl - ODBC with SQL Serverkafka_streaming_example.xdl - Kafka streaming operationsTo add support for a new database:
Cargo.tomlsrc/drivers/connect()execute()execute_command()close()is_connected()DatabaseConnection enumGPL-2.0 (same as XDL)
For issues and questions: