1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// Copyright (c) 2025-2026 Adrian Robinson. Licensed under the AGPL-3.0.
// See LICENSE file in the project root for full license text.
//! Search Infrastructure
//!
//! Full-text search across items using RediSearch and MySQL.
//!
//! # Architecture
//!
//! ```text
//! QueryBuilder (AST)
//! ↓
//! ├─→ RediSearchTranslator → FT.SEARCH syntax
//! └─→ SqlTranslator → MySQL JSON_EXTRACT queries
//! ```
//!
//! # Index Registration
//!
//! sync-engine stays "dumb" about content but provides index lifecycle management:
//!
//! ```rust,no_run
//! # use sync_engine::{SyncEngine, search::{SearchIndex, Query}};
//! # async fn example(engine: &SyncEngine) {
//! // Register schema at startup using builder pattern
//! let index = SearchIndex::new("users", "crdt:users:")
//! .text_sortable("name")
//! .text("email")
//! .numeric_sortable("age")
//! .tag("roles");
//!
//! engine.create_search_index(index).await.unwrap();
//!
//! // RediSearch auto-indexes matching JSON documents
//! // Search using Query AST
//! let query = Query::field_eq("name", "Alice");
//! let results = engine.search("users", &query).await.unwrap();
//! # }
//! ```
//!
//! # Query Language (Lucene/RediSearch syntax)
//!
//! ```text
//! @name:Alice - Field equals
//! @age:[25 40] - Numeric range
//! @tags:{rust|database} - Tag membership (OR)
//! @name:Alice AND @age:[25 40] - Boolean AND
//! @status:active | @status:pending - Boolean OR
//! -@deleted:true - Boolean NOT
//! @name:*alice* - Wildcard contains
//! @name:ali* - Prefix match
//! @name:%alice% - Fuzzy match (Levenshtein)
//! (filter)=>[KNN 10 @embedding $blob] - Vector KNN search
//! ```
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;