mirror of
https://github.com/aljazceru/turso.git
synced 2025-12-25 12:04:21 +01:00
Add documentation/example to extensions/core README.md
This commit is contained in:
@@ -10,7 +10,7 @@ like traditional `sqlite3` extensions, but are able to be written in much more e
|
||||
- [ x ] **Scalar Functions**: Create scalar functions using the `scalar` macro.
|
||||
- [ x ] **Aggregate Functions**: Define aggregate functions with `AggregateDerive` macro and `AggFunc` trait.
|
||||
- [ x ] **Virtual tables**: Create a module for a virtual table with the `VTabModuleDerive` macro and `VTabCursor` trait.
|
||||
- [] **VFS Modules**
|
||||
- [ x ] **VFS Modules**: Extend Limbo's OS interface by implementing `VfsExtension` and `VfsFile` traits.
|
||||
---
|
||||
|
||||
## Installation
|
||||
@@ -279,6 +279,106 @@ impl VTabCursor for CsvCursor {
|
||||
}
|
||||
```
|
||||
|
||||
### VFS Example
|
||||
|
||||
|
||||
```rust
|
||||
use limbo_ext::{ExtResult as Result, VfsDerive, VfsExtension, VfsFile};
|
||||
|
||||
/// Your struct must also impl Default
|
||||
#[derive(VfsDerive, Default)]
|
||||
struct ExampleFS;
|
||||
|
||||
|
||||
struct ExampleFile {
|
||||
file: std::fs::File,
|
||||
}
|
||||
|
||||
impl VfsExtension for ExampleFS {
|
||||
/// The name of your vfs module
|
||||
const NAME: &'static str = "example";
|
||||
|
||||
type File = ExampleFile;
|
||||
|
||||
fn open(&self, path: &str, flags: i32, _direct: bool) -> Result<Self::File> {
|
||||
let file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(flags & 1 != 0)
|
||||
.open(path)
|
||||
.map_err(|_| ResultCode::Error)?;
|
||||
Ok(TestFile { file })
|
||||
}
|
||||
|
||||
fn run_once(&self) -> Result<()> {
|
||||
// (optional) method to cycle/advance IO, if your extension is asynchronous
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn close(&self, file: Self::File) -> Result<()> {
|
||||
// (optional) method to close or drop the file
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn generate_random_number(&self) -> i64 {
|
||||
// (optional) method to generate random number. Used for testing
|
||||
let mut buf = [0u8; 8];
|
||||
getrandom::fill(&mut buf).unwrap();
|
||||
i64::from_ne_bytes(buf)
|
||||
}
|
||||
|
||||
fn get_current_time(&self) -> String {
|
||||
// (optional) method to generate random number. Used for testing
|
||||
chrono::Local::now().format("%Y-%m-%d %H:%M:%S").to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl VfsFile for ExampleFile {
|
||||
fn read(
|
||||
&mut self,
|
||||
buf: &mut [u8],
|
||||
count: usize,
|
||||
offset: i64,
|
||||
) -> Result<i32> {
|
||||
if file.file.seek(SeekFrom::Start(offset as u64)).is_err() {
|
||||
return Err(ResultCode::Error);
|
||||
}
|
||||
file.file
|
||||
.read(&mut buf[..count])
|
||||
.map_err(|_| ResultCode::Error)
|
||||
.map(|n| n as i32)
|
||||
}
|
||||
|
||||
fn write(&mut self, buf: &[u8], count: usize, offset: i64) -> Result<i32> {
|
||||
if self.file.seek(SeekFrom::Start(offset as u64)).is_err() {
|
||||
return Err(ResultCode::Error);
|
||||
}
|
||||
self.file
|
||||
.write(&buf[..count])
|
||||
.map_err(|_| ResultCode::Error)
|
||||
.map(|n| n as i32)
|
||||
}
|
||||
|
||||
fn sync(&self) -> Result<()> {
|
||||
self.file.sync_all().map_err(|_| ResultCode::Error)
|
||||
}
|
||||
|
||||
fn lock(&self, _exclusive: bool) -> Result<()> {
|
||||
// (optional) method to lock the file
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn unlock(&self) -> Result<()> {
|
||||
// (optional) method to lock the file
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn size(&self) -> i64 {
|
||||
self.file.metadata().map(|m| m.len() as i64).unwrap_or(-1)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Cargo.toml Config
|
||||
|
||||
Edit the workspace `Cargo.toml` to include your extension as a workspace dependency, e.g:
|
||||
|
||||
Reference in New Issue
Block a user