Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion plugins/tantivy/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,27 @@ authors = ["You"]
edition = "2024"
exclude = ["/js", "/node_modules"]
links = "tauri-plugin-tantivy"
description = ""
description = "Full-text search plugin using Tantivy"

[build-dependencies]
tauri-plugin = { workspace = true, features = ["build"] }

[dev-dependencies]
specta-typescript = { workspace = true }
tempfile = { workspace = true }
tokio = { workspace = true, features = ["macros"] }

[dependencies]
tantivy = "0.22"

tauri = { workspace = true, features = ["test"] }
tauri-plugin-path2 = { workspace = true }
tauri-specta = { workspace = true, features = ["derive", "typescript"] }

serde = { workspace = true }
serde_json = { workspace = true }
specta = { workspace = true }

thiserror = { workspace = true }
tokio = { workspace = true }
tracing = { workspace = true }
206 changes: 147 additions & 59 deletions plugins/tantivy/js/bindings.gen.ts
Original file line number Diff line number Diff line change
@@ -1,77 +1,165 @@
// @ts-nocheck

// This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually.

/** user-defined commands **/


export const commands = {
async ping() : Promise<Result<null, string>> {
try {
return { status: "ok", data: await TAURI_INVOKE("plugin:tantivy|ping") };
} catch (e) {
if(e instanceof Error) throw e;
else return { status: "error", error: e as any };
}
},
async init() : Promise<Result<null, string>> {
try {
return { status: "ok", data: await TAURI_INVOKE("plugin:tantivy|init") };
} catch (e) {
if(e instanceof Error) throw e;
else return { status: "error", error: e as any };
}
},
async addDocument(doc: SearchDocument) : Promise<Result<null, string>> {
try {
return { status: "ok", data: await TAURI_INVOKE("plugin:tantivy|add_document", { doc }) };
} catch (e) {
if(e instanceof Error) throw e;
else return { status: "error", error: e as any };
}
},
async updateDocument(doc: SearchDocument) : Promise<Result<null, string>> {
try {
return { status: "ok", data: await TAURI_INVOKE("plugin:tantivy|update_document", { doc }) };
} catch (e) {
if(e instanceof Error) throw e;
else return { status: "error", error: e as any };
}
},
async deleteDocument(id: string) : Promise<Result<null, string>> {
try {
return { status: "ok", data: await TAURI_INVOKE("plugin:tantivy|delete_document", { id }) };
} catch (e) {
if(e instanceof Error) throw e;
else return { status: "error", error: e as any };
}
},
async commit() : Promise<Result<null, string>> {
try {
return { status: "ok", data: await TAURI_INVOKE("plugin:tantivy|commit") };
} catch (e) {
if(e instanceof Error) throw e;
else return { status: "error", error: e as any };
}
},
async search(query: string, filters: SearchFilters | null, limit: number | null) : Promise<Result<SearchResult, string>> {
try {
return { status: "ok", data: await TAURI_INVOKE("plugin:tantivy|search", { query, filters, limit }) };
} catch (e) {
if(e instanceof Error) throw e;
else return { status: "error", error: e as any };
}
},
async searchFuzzy(query: string, filters: SearchFilters | null, limit: number | null, distance: number | null) : Promise<Result<SearchResult, string>> {
try {
return { status: "ok", data: await TAURI_INVOKE("plugin:tantivy|search_fuzzy", { query, filters, limit, distance }) };
} catch (e) {
if(e instanceof Error) throw e;
else return { status: "error", error: e as any };
}
},
async clear() : Promise<Result<null, string>> {
try {
return { status: "ok", data: await TAURI_INVOKE("plugin:tantivy|clear") };
} catch (e) {
if(e instanceof Error) throw e;
else return { status: "error", error: e as any };
}
},
async count() : Promise<Result<number, string>> {
try {
return { status: "ok", data: await TAURI_INVOKE("plugin:tantivy|count") };
} catch (e) {
if(e instanceof Error) throw e;
else return { status: "error", error: e as any };
}
}
}

/** user-defined events **/



/** user-defined constants **/



/** user-defined types **/

export type CreatedAtFilter = { gte: number | null; lte: number | null; gt: number | null; lt: number | null; eq: number | null }
export type SearchDocument = { id: string; doc_type: string; title: string; content: string; created_at: number }
export type SearchFilters = { created_at: CreatedAtFilter | null }
export type SearchHit = { score: number; document: SearchDocument }
export type SearchResult = { hits: SearchHit[] }

/** tauri-specta globals **/

import {
Channel as TAURI_CHANNEL,
invoke as TAURI_INVOKE,
invoke as TAURI_INVOKE,
Channel as TAURI_CHANNEL,
} from "@tauri-apps/api/core";
import * as TAURI_API_EVENT from "@tauri-apps/api/event";
import { type WebviewWindow as __WebviewWindow__ } from "@tauri-apps/api/webviewWindow";

// This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually.

/** user-defined commands **/

export const commands = {
async ping(): Promise<Result<null, string>> {
try {
return { status: "ok", data: await TAURI_INVOKE("plugin:tantivy|ping") };
} catch (e) {
if (e instanceof Error) throw e;
else return { status: "error", error: e as any };
}
},
};

type __EventObj__<T> = {
listen: (
cb: TAURI_API_EVENT.EventCallback<T>,
) => ReturnType<typeof TAURI_API_EVENT.listen<T>>;
once: (
cb: TAURI_API_EVENT.EventCallback<T>,
) => ReturnType<typeof TAURI_API_EVENT.once<T>>;
emit: null extends T
? (payload?: T) => ReturnType<typeof TAURI_API_EVENT.emit>
: (payload: T) => ReturnType<typeof TAURI_API_EVENT.emit>;
listen: (
cb: TAURI_API_EVENT.EventCallback<T>,
) => ReturnType<typeof TAURI_API_EVENT.listen<T>>;
once: (
cb: TAURI_API_EVENT.EventCallback<T>,
) => ReturnType<typeof TAURI_API_EVENT.once<T>>;
emit: null extends T
? (payload?: T) => ReturnType<typeof TAURI_API_EVENT.emit>
: (payload: T) => ReturnType<typeof TAURI_API_EVENT.emit>;
};

export type Result<T, E> =
| { status: "ok"; data: T }
| { status: "error"; error: E };
| { status: "ok"; data: T }
| { status: "error"; error: E };

function __makeEvents__<T extends Record<string, any>>(
mappings: Record<keyof T, string>,
mappings: Record<keyof T, string>,
) {
return new Proxy(
{} as unknown as {
[K in keyof T]: __EventObj__<T[K]> & {
(handle: __WebviewWindow__): __EventObj__<T[K]>;
};
},
{
get: (_, event) => {
const name = mappings[event as keyof T];

return new Proxy((() => {}) as any, {
apply: (_, __, [window]: [__WebviewWindow__]) => ({
listen: (arg: any) => window.listen(name, arg),
once: (arg: any) => window.once(name, arg),
emit: (arg: any) => window.emit(name, arg),
}),
get: (_, command: keyof __EventObj__<any>) => {
switch (command) {
case "listen":
return (arg: any) => TAURI_API_EVENT.listen(name, arg);
case "once":
return (arg: any) => TAURI_API_EVENT.once(name, arg);
case "emit":
return (arg: any) => TAURI_API_EVENT.emit(name, arg);
}
},
});
},
},
);
return new Proxy(
{} as unknown as {
[K in keyof T]: __EventObj__<T[K]> & {
(handle: __WebviewWindow__): __EventObj__<T[K]>;
};
},
{
get: (_, event) => {
const name = mappings[event as keyof T];

return new Proxy((() => {}) as any, {
apply: (_, __, [window]: [__WebviewWindow__]) => ({
listen: (arg: any) => window.listen(name, arg),
once: (arg: any) => window.once(name, arg),
emit: (arg: any) => window.emit(name, arg),
}),
get: (_, command: keyof __EventObj__<any>) => {
switch (command) {
case "listen":
return (arg: any) => TAURI_API_EVENT.listen(name, arg);
case "once":
return (arg: any) => TAURI_API_EVENT.once(name, arg);
case "emit":
return (arg: any) => TAURI_API_EVENT.emit(name, arg);
}
},
});
},
},
);
}
91 changes: 90 additions & 1 deletion plugins/tantivy/src/commands.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,96 @@
use crate::TantivyPluginExt;
use crate::{SearchDocument, SearchFilters, SearchResult, TantivyPluginExt};

#[tauri::command]
#[specta::specta]
pub(crate) async fn ping<R: tauri::Runtime>(app: tauri::AppHandle<R>) -> Result<(), String> {
app.tantivy().ping().map_err(|e| e.to_string())
}

#[tauri::command]
#[specta::specta]
pub(crate) async fn init<R: tauri::Runtime>(app: tauri::AppHandle<R>) -> Result<(), String> {
app.tantivy().init().await.map_err(|e| e.to_string())
}

#[tauri::command]
#[specta::specta]
pub(crate) async fn add_document<R: tauri::Runtime>(
app: tauri::AppHandle<R>,
doc: SearchDocument,
) -> Result<(), String> {
app.tantivy()
.add_document(doc)
.await
.map_err(|e| e.to_string())
}

#[tauri::command]
#[specta::specta]
pub(crate) async fn update_document<R: tauri::Runtime>(
app: tauri::AppHandle<R>,
doc: SearchDocument,
) -> Result<(), String> {
app.tantivy()
.update_document(doc)
.await
.map_err(|e| e.to_string())
}

#[tauri::command]
#[specta::specta]
pub(crate) async fn delete_document<R: tauri::Runtime>(
app: tauri::AppHandle<R>,
id: String,
) -> Result<(), String> {
app.tantivy()
.delete_document(id)
.await
.map_err(|e| e.to_string())
}

#[tauri::command]
#[specta::specta]
pub(crate) async fn commit<R: tauri::Runtime>(app: tauri::AppHandle<R>) -> Result<(), String> {
app.tantivy().commit().await.map_err(|e| e.to_string())
}

#[tauri::command]
#[specta::specta]
pub(crate) async fn search<R: tauri::Runtime>(
app: tauri::AppHandle<R>,
query: String,
filters: Option<SearchFilters>,
limit: Option<usize>,
) -> Result<SearchResult, String> {
app.tantivy()
.search(query, filters, limit.unwrap_or(100))
.await
.map_err(|e| e.to_string())
}

#[tauri::command]
#[specta::specta]
pub(crate) async fn search_fuzzy<R: tauri::Runtime>(
app: tauri::AppHandle<R>,
query: String,
filters: Option<SearchFilters>,
limit: Option<usize>,
distance: Option<u8>,
) -> Result<SearchResult, String> {
app.tantivy()
.search_fuzzy(query, filters, limit.unwrap_or(100), distance.unwrap_or(1))
.await
.map_err(|e| e.to_string())
}

#[tauri::command]
#[specta::specta]
pub(crate) async fn clear<R: tauri::Runtime>(app: tauri::AppHandle<R>) -> Result<(), String> {
app.tantivy().clear().await.map_err(|e| e.to_string())
}

#[tauri::command]
#[specta::specta]
pub(crate) async fn count<R: tauri::Runtime>(app: tauri::AppHandle<R>) -> Result<u64, String> {
app.tantivy().count().await.map_err(|e| e.to_string())
}
14 changes: 14 additions & 0 deletions plugins/tantivy/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@ pub type Result<T> = std::result::Result<T, Error>;
pub enum Error {
#[error(transparent)]
Io(#[from] std::io::Error),
#[error(transparent)]
Tantivy(#[from] tantivy::TantivyError),
#[error(transparent)]
QueryParser(#[from] tantivy::query::QueryParserError),
#[error(transparent)]
Tauri(#[from] tauri::Error),
#[error(transparent)]
Path2(#[from] tauri_plugin_path2::Error),
#[error("Index not initialized")]
IndexNotInitialized,
#[error("Document not found: {0}")]
DocumentNotFound(String),
#[error("Invalid document type: {0}")]
InvalidDocumentType(String),
}

impl Serialize for Error {
Expand Down
Loading
Loading