1use crate::connection::Connection;
2use crate::error::{Error, Result};
3use crate::worker::WorkerClient;
4use neug_protocol::{RequestPayload, ResponsePayload};
5use std::path::Path;
6use std::sync::Arc;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum Mode {
10 ReadOnly,
11 ReadWrite,
12}
13
14impl Mode {
15 pub fn as_str(&self) -> &'static str {
16 match self {
17 Mode::ReadOnly => "read-only",
18 Mode::ReadWrite => "read-write",
19 }
20 }
21}
22
23pub struct DatabaseOptions {
24 pub db_path: String,
25 pub mode: Mode,
26 pub max_thread_num: usize,
27 pub checkpoint_on_close: bool,
28}
29
30impl Default for DatabaseOptions {
31 fn default() -> Self {
32 Self {
33 db_path: String::new(),
34 mode: Mode::ReadWrite,
35 max_thread_num: 0,
36 checkpoint_on_close: true,
37 }
38 }
39}
40
41pub struct Database {
42 db_id: u64,
43 worker: Arc<WorkerClient>,
44 options: DatabaseOptions,
45}
46
47impl Database {
48 pub fn open<P: AsRef<Path>>(db_path: P, mode: Mode) -> Result<Self> {
51 let options = DatabaseOptions {
52 db_path: db_path.as_ref().to_string_lossy().into_owned(),
53 mode,
54 ..Default::default()
55 };
56 Self::with_options(options)
57 }
58
59 pub fn with_options(options: DatabaseOptions) -> Result<Self> {
61 let worker = Arc::new(WorkerClient::spawn()?);
62
63 let res = worker.send_request(RequestPayload::OpenDb {
64 path: options.db_path.clone(),
65 mode: options.mode.as_str().to_string(),
66 max_thread_num: options.max_thread_num,
67 checkpoint_on_close: options.checkpoint_on_close,
68 })?;
69
70 match res {
71 ResponsePayload::OkDb { db_id } => Ok(Self {
72 db_id,
73 worker,
74 options,
75 }),
76 ResponsePayload::Error(msg) => Err(Error::InitializationFailed(msg)),
77 _ => Err(Error::InitializationFailed("Unexpected response".into())),
78 }
79 }
80
81 pub fn mode(&self) -> Mode {
83 self.options.mode
84 }
85
86 pub fn connect(&self) -> Result<Connection> {
88 let res = self
89 .worker
90 .send_request(RequestPayload::Connect { db_id: self.db_id })?;
91
92 match res {
93 ResponsePayload::OkConn { conn_id } => {
94 Ok(Connection::new(conn_id, self.worker.clone()))
95 }
96 ResponsePayload::Error(msg) => Err(Error::InitializationFailed(msg)),
97 _ => Err(Error::InitializationFailed("Unexpected response".into())),
98 }
99 }
100
101 pub fn close(&mut self) {
103 if self.db_id != 0 {
104 let _ = self
105 .worker
106 .send_request(RequestPayload::CloseDb { db_id: self.db_id });
107 self.db_id = 0;
108 }
109 }
110}
111
112impl Drop for Database {
113 fn drop(&mut self) {
114 self.close();
115 }
116}