Skip to content

Commit 201c161

Browse files
committed
Made check subcommand compatible with sqlite db
1 parent 6f3b6fb commit 201c161

4 files changed

Lines changed: 77 additions & 44 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ This command allows you to quickly check how many documents are present in a sav
7070
**Syntax:**
7171

7272
```bash
73-
DocSense check [input_index_file.json]
73+
./target/release/DocSense check [input_index_file.json]
7474
```
7575

7676
* `[input_index_file.json]` (Optional): The path to the index file to check. Defaults to `index.json`.
@@ -88,7 +88,7 @@ This command starts an HTTP server that allows you to submit search queries and
8888
**Syntax:**
8989

9090
```bash
91-
DocSense serve <input_index_file.json> [address]
91+
./target/release/DocSense serve <input_index_file.json> [address]
9292
```
9393

9494
* `<input_index_file.json>`: The path to the index file you want to use for searching.

src/main.rs

Lines changed: 52 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std:: {
44

55
use xml::{self, reader::XmlEvent, EventReader};
66
use xml::common::{TextPosition, Position};
7-
use colored::Colorize;
7+
use colored::{ColoredString, Colorize};
88

99
mod lexer;
1010
mod server;
@@ -13,7 +13,7 @@ mod model;
1313
use crate::model::{InMemoryModel, Model, SqliteModel};
1414

1515
/* Parse all the text (Character Events) from the XML File */
16-
fn read_xml_file(file_path: &Path) -> Result<String, ()> {
16+
fn parse_xml_file(file_path: &Path) -> Result<String, ()> {
1717
let file = File::open(file_path).map_err(|err| {
1818
eprintln!("{}: Could not open file {file_path}: {err}", "ERROR".bold().red(), file_path = file_path.display());
1919
})?;
@@ -84,21 +84,22 @@ fn append_folder_to_model(dir_path: &Path, model: &mut dyn Model) -> Result<(),
8484

8585
// Recursively index all the folders
8686
if file_type.is_dir() {
87-
let _ = append_folder_to_model(&file_path, model);
87+
append_folder_to_model(&file_path, model)?;
8888
continue 'step;
8989
}
9090

9191
println!("Indexing {} ...", file_path_str.bright_cyan());
9292

93-
let content = match read_xml_file(&file_path) {
93+
let content = match parse_xml_file(&file_path) {
9494
Ok(content) => content.chars().collect::<Vec<_>>(),
9595
Err(err) => {
9696
eprintln!("{error}: Failed to read xml file {fp}: {msg:?}", error = "ERROR".bold().red(), fp = file_path.to_str().unwrap().bright_blue(), msg = err);
9797
continue 'step;
9898
}
9999
};
100100

101-
let _ = model.add_document(file_path, &content);
101+
// Core Operation
102+
model.add_document(file_path, &content)?;
102103
}
103104
Ok(())
104105
}
@@ -110,25 +111,28 @@ fn check_index(index_path: &str) -> Result<(), ()> {
110111
exit(1);
111112
})?;
112113

113-
println!("{info}: Reading file {file}", info = "INFO".bright_cyan(), file = index_path.bright_blue());
114+
println!("{info}: Reading file {file}", info = "INFO".cyan(), file = index_path.bright_blue());
114115
let model: InMemoryModel = serde_json::from_reader(BufReader::new(index_file)).map_err(|err| {
115116
eprintln!("{}: Serde could not read file {file} as \"{err}\"", "ERROR".bold().red(), file = index_path.bright_blue(), err = err.to_string().red());
116117
exit(1);
117118
})?;
118-
println!("{info}: Index file has {entries} entries", info = "INFO".bright_cyan(), entries = model.tf_index.len());
119+
println!("{info}: Index file has {entries} entries", info = "INFO".cyan(), entries = model.tf_index.len());
119120
Ok(())
120121
}
121122

122-
const DEFAULT_INDEX_FILE_PATH: &str = "index.json";
123+
const DEFAULT_INDEX_JSON_PATH: &str = "index.json";
124+
const DEFAULT_INDEX_SQLITE_DB_PATH: &str = "index.db";
125+
123126

124127
fn fetch_model(index_path: &str) -> Result<InMemoryModel, ()> {
125128
let index_file = fs::File::open(&index_path).map_err(|err| {
126129
eprintln!("{}: Could not open file {file_path} as \"{err}\"", "ERROR".bold().red(), file_path = index_path.bright_blue(), err = err.to_string().red());
127-
})?;
130+
}).unwrap();
128131

129132
let model: InMemoryModel = serde_json::from_reader(BufReader::new(index_file)).map_err(|err| {
130133
eprintln!("{}: Serde failed to read {file_path} as \"{err}\"", "ERROR".bold().red(), file_path = index_path.bright_blue(), err = err.to_string().red());
131-
})?;
134+
}).unwrap();
135+
132136
return Ok(model);
133137
}
134138

@@ -143,12 +147,11 @@ fn usage(program: &String) {
143147

144148
fn entry() -> Result<(), ()> {
145149
let mut args = env::args();
146-
let program = args.next().expect("Path to program must be provided.");
150+
let program = args.next().expect("path to program is provided");
147151

148-
let mut use_sqlite_mode = false;
149152
let mut subcommand = None;
153+
let mut use_sqlite_mode = false;
150154

151-
// Look for --sqlite flag
152155
while let Some(arg) = args.next() {
153156
match arg.as_str() {
154157
"--sqlite" => use_sqlite_mode = true,
@@ -159,28 +162,29 @@ fn entry() -> Result<(), ()> {
159162
}
160163
}
161164

162-
let subcommand = args.next().unwrap_or_else(|| {
165+
let subcommand = subcommand.ok_or_else(|| {
163166
usage(&program);
164-
eprintln!("{}: no subcommand is provided.", "ERROR".bold().red());
165-
exit(0);
166-
});
167-
167+
eprintln!("ERROR: no subcommand is provided");
168+
})?;
168169

169170
match subcommand.as_str() {
170171
"index" => {
171-
let dir_path = args.next().unwrap_or_else(|| {
172+
let dir_path = args.next().ok_or_else(|| {
173+
usage(&program);
172174
eprintln!("{}: No directory path is provided for {} subcommand.", "ERROR".bold().red(), subcommand.bold().bright_blue());
173-
exit(1);
174-
});
175+
})?;
175176

176177
if use_sqlite_mode {
177178
let index_path = "index.db";
178179

179180
// Remove previous index.db to update
180-
if let Err(err) = fs::remove_file(index_path) {
181-
eprintln!("{}: Could not delete file {path} as \"{err:?}\"", "ERROR".bold().red(), path = dir_path.bold().bright_blue(), err = err.to_string().red());
182-
return Err(());
181+
if Path::exists(Path::new(index_path)) {
182+
if let Err(err) = fs::remove_file(index_path) {
183+
eprintln!("{}: Could not delete file {path} as \"{err}\"", "ERROR".bold().red(), path = index_path.bold().bright_blue(), err = err.to_string().red());
184+
return Err(());
185+
}
183186
}
187+
184188
let mut model = SqliteModel::open(Path::new(index_path)).unwrap();
185189
model.begin()?;
186190
append_folder_to_model(Path::new(&dir_path), &mut model)?;
@@ -195,15 +199,15 @@ fn entry() -> Result<(), ()> {
195199
}
196200

197201
"search" => {
198-
let index_path = args.next().unwrap_or_else(|| {
202+
let index_path = args.next().ok_or_else(|| {
203+
usage(&program);
199204
eprintln!("{}: Index file path must provided for {} subcommand.", "ERROR".bold().red(), subcommand.bold().bright_blue());
200-
exit(1);
201-
});
205+
})?;
202206

203-
let prompt = args.next().unwrap_or_else(|| {
207+
let prompt = args.next().ok_or_else(|| {
208+
usage(&program);
204209
eprintln!("{}: Prompt must be provided for {} subcommand.", "ERROR".bold().red(), subcommand.bold().bright_blue());
205-
exit(1);
206-
}).chars().collect::<Vec<char>>();
210+
})?.chars().collect::<Vec<char>>();
207211

208212

209213
if use_sqlite_mode {
@@ -222,35 +226,43 @@ fn entry() -> Result<(), ()> {
222226
}
223227

224228
"check" => {
225-
// TODO: Make it compatible with Sqlite db
226-
let index_path = args.next().unwrap_or(DEFAULT_INDEX_FILE_PATH.to_string());
227-
check_index(&index_path).unwrap();
229+
if use_sqlite_mode {
230+
let index_path = args.next().unwrap_or(DEFAULT_INDEX_SQLITE_DB_PATH.to_string());
231+
let model = SqliteModel::open(Path::new(&index_path))?;
232+
println!("{info}: Database has {count} entries.", info = "INFO".cyan(), count = model.check().unwrap());
233+
} else {
234+
let index_path = args.next().unwrap_or(DEFAULT_INDEX_JSON_PATH.to_string());
235+
check_index(&index_path).unwrap();
236+
}
228237
}
229238

230239
"serve" => {
231-
let index_path = args.next().unwrap_or_else(|| {
240+
let index_path = args.next().ok_or_else(|| {
241+
usage(&program);
232242
eprintln!("{}: Index file path must provided for {} subcommand.", "ERROR".bold().red(), subcommand.bold().bright_blue());
233-
exit(1);
234-
});
235-
243+
})?;
244+
236245
// Default address
237246
let address = args.next().unwrap_or("127.0.0.1:6969".to_string());
238247

239248
if use_sqlite_mode {
240249
let model = SqliteModel::open(Path::new(&index_path))?;
241250
return server::start(&address, &model);
251+
242252
} else {
243-
let model: InMemoryModel = fetch_model(&index_path).unwrap();
253+
let model: InMemoryModel = fetch_model(&index_path).unwrap_or_else(|()| {
254+
eprintln!("{}: Failed to fetch model for {}.", "ERROR".bold().red(), index_path.bright_blue());
255+
exit(1);
256+
});
244257
return server::start(&address, &model);
245258
}
246-
247259
}
248260

249261
_ => {
250262

251263
usage(&program);
252264
eprintln!("{}: Unknown subcommand {}", "ERROR".bold().red(), subcommand.bold().bright_blue());
253-
exit(1);
265+
return Err(());
254266
}
255267
}
256268
Ok(())

src/model.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,28 @@ impl SqliteModel {
7777

7878
Ok(this)
7979
}
80+
81+
pub fn check(&self) -> Result<u64, ()> {
82+
let count = {
83+
let query = "SELECT COUNT(*) as count FROM Documents";
84+
let log_err = |err: sqlite::Error| {
85+
eprintln!("{ERROR}: Could not execute query {query} as {err}", ERROR = "ERROR".bold().red(), err = err.to_string().red());
86+
};
87+
88+
let mut stmt = self.connection.prepare(query).map_err(log_err)?;
89+
match stmt.next().map_err(log_err)? {
90+
sqlite::State::Row => stmt.read::<i64, _>("count").map_err(log_err)?,
91+
sqlite::State::Done => 0,
92+
}
93+
};
94+
Ok(count as u64)
95+
}
96+
8097
}
8198

8299
impl Model for SqliteModel {
83100
fn search_query(&self, query: &[char]) -> Result<Vec<(PathBuf, f32)>, ()> {
84-
todo!("SqliteModel::search_query()")
101+
todo!("SqliteModel::search_query()");
85102
}
86103

87104
fn add_document(&mut self, path: PathBuf, content: &[char]) -> Result<(), ()> {

src/server.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,11 @@ pub fn serve_api_search(mut request: Request, model: &impl Model) -> io::Result<
5555

5656
println!("Recieved Query: \'{}\'", body.iter().collect::<String>().bright_blue());
5757

58-
let results = model.search_query(&body).unwrap();
58+
// Main -> Get results from model
59+
let results = match model.search_query(&body) {
60+
Ok(results) => results,
61+
Err(()) => return serve_500(request)
62+
};
5963

6064
// Display document ranks
6165
for (path, rank) in results.iter().take(10) {

0 commit comments

Comments
 (0)