A Flutter package for interacting with Cloudflare D1 databases via REST API.
- ✅ Type Safety: Strongly typed responses and configurations
- ✅ High-Level Operations: Built-in methods for common database operations
- ✅ Batch Operations: Execute multiple queries efficiently
- ✅ Error Handling: Comprehensive error handling with custom exceptions
- ✅ Prepared Statements: Support for parameterized queries
- ✅ Schema Management: Table creation, modification, and introspection
Add this to your package's pubspec.yaml file:
dependencies:
cloudflare_d1:
git:
url: https://github.com/yabzec/cloudflare_d1.git
ref: mainThen run:
flutter pub getfinal config = D1Config(
accountId: 'your-cloudflare-account-id',
databaseId: 'your-d1-database-id',
apiToken: 'your-cloudflare-api-token',
);final client = D1Client(config: config);
final database = D1Database(client);await database.createTable(
'users',
{
'id': 'INTEGER PRIMARY KEY AUTOINCREMENT',
'name': 'TEXT NOT NULL',
'email': 'TEXT UNIQUE NOT NULL',
'created_at': 'DATETIME DEFAULT CURRENT_TIMESTAMP',
},
);final response = await database.insert('users', {
'name': 'John Doe',
'email': 'john@example.com',
});
print('Inserted with ID: ${response.lastRowId}');// Select all users
final allUsers = await database.select('users');
// Select with conditions
final activeUsers = await database.select(
'users',
where: 'status = ?',
whereParams: ['active'],
orderBy: 'created_at DESC',
limit: 10,
);
// Find by ID
final user = await database.findById('users', 1);final response = await database.update(
'users',
{'name': 'Jane Doe', 'email': 'jane@example.com'},
where: 'id = ?',
whereParams: [1],
);
print('Updated ${response.changes} rows');final response = await database.delete(
'users',
where: 'id = ?',
whereParams: [1],
);
print('Deleted ${response.changes} rows');// Simple query
final response = await database.execute('SELECT * FROM users WHERE age > 18');
// Parameterized query
final response = await database.execute(
'SELECT * FROM users WHERE status = ? AND created_at > ?',
['active', DateTime.now().subtract(Duration(days: 30)).toIso8601String()],
);
// Access results
for (final row in response.allResults) {
print('User: ${row['name']} (${row['email']})');
}final queries = [
D1Query.simple('SELECT COUNT(*) FROM users'),
D1Query.simple('SELECT COUNT(*) FROM posts'),
D1Query.withParams('SELECT * FROM users WHERE id = ?', [1]),
];
final results = await database.batch(queries);
for (final result in results) {
print('Query result: ${result.allResults}');
}// Check if table exists
final exists = await database.tableExists('users');
// Get table schema
final schema = await database.getTableSchema('users');
for (final column in schema) {
print('Column: ${column['name']} (${column['type']})');
}The package provides comprehensive error handling:
try {
final result = await database.execute('SELECT * FROM non_existent_table');
} on D1Exception catch (e) {
switch (e.runtimeType) {
case D1Exception:
if (e.statusCode != null) {
print('API Error ${e.statusCode}: ${e.message}');
} else {
print('Database Error: ${e.message}');
}
if (e.details != null) {
print('Details: ${e.details}');
}
break;
default:
print('Unknown error: $e');
}
} catch (e) {
print('Unexpected error: $e');
}| Property | Type | Description |
|---|---|---|
accountId |
String? |
Cloudflare account ID (for REST API) |
databaseId |
String? |
D1 database ID (for REST API) |
apiToken |
String? |
Cloudflare API token (for REST API) |
customHeaders |
Map<String, String> |
Additional headers for requests |
timeout |
Duration |
Request timeout (default: 30 seconds) |
execute(sql, [params])- Execute raw SQLselect(table, {options})- Select recordsinsert(table, data)- Insert a recordupdate(table, data, {where, whereParams})- Update recordsdelete(table, {where, whereParams})- Delete recordscount(table, {where, whereParams})- Count records
findById(table, id)- Find record by IDfindBy(table, field, value)- Find records by fieldfirst(table, {options})- Get first matching recordexists(table, {where, whereParams})- Check if records exist
createTable(name, columns, {options})- Create tabledropTable(name, {ifExists})- Drop tabletableExists(name)- Check if table existsgetTableSchema(name)- Get table schema
batch(queries)- Execute multiple queries