Skip to content

Commit 6166f03

Browse files
committed
Iterate with column family command
1 parent 9eedfe2 commit 6166f03

File tree

12 files changed

+162
-156
lines changed

12 files changed

+162
-156
lines changed

Cargo.lock

-18
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ OPTIONS:
7979
| ------------------------------------------------------ | -------------------------------- |
8080
| <kbd>ENTER</kbd> | Enter focused section |
8181
| <kbd>ESC</kbd> | Escape from focused section |
82+
| <kbd>9</kbd>, <kbd>0</kbd> | Scroll up/down databases |
8283
| <kbd>h</kbd>, <kbd>j</kbd> | Scroll up/down key byte layout |
8384
| <kbd>k</kbd>, <kbd>l</kbd> | Scroll up/down value byte layout |
8485
| <kbd>←</kbd>, <kbd>→</kbd>, <kbd>↑</kbd>, <kbd>↓</kbd> | Move focus to left/right/up/down |

config-example.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
},
77
{
88
"name": "rocksdb",
9-
"path": "../temp/v2"
9+
"path": "../temp/cf"
1010
},
1111
{
1212
"name": "redb",

db/Cargo.toml

-2
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,8 @@ thiserror = "1.0.37"
3838
async-trait = "0.1.58"
3939
futures = "0.3.25"
4040
rand = "0.8.5"
41-
uuid = { version = "1.2.1", features = ["v4"] }
4241
serde_json = "1.0.87"
4342
lazy_static = "1.4.0"
44-
byteorder = "1.4.3"
4543
serde = { version = "1.0.147", features = ["derive"] }
4644
log = "0.4.17"
4745
path-absolutize = "3.0.14"

db/src/storage/ds.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -120,20 +120,18 @@ mod test {
120120

121121
#[tokio::test]
122122
async fn should_create() {
123-
let db = Datastore::new("rocksdb:../temp/redb");
123+
let db = Datastore::new("redb:../temp/redb");
124124
assert!(db.transaction(false).is_ok());
125125

126126
// Seeding database
127-
// let cf_name = COLUMN_FAMILIES.get(&ColumnFamily::TestSuite).unwrap();
128-
// let cf = Some(cf_name.to_string().into());
129127
let cf = None;
130128

131129
let key1 = i32::to_be_bytes(2001);
132-
let key2 = "hello world";
130+
let key2 = "new key new data hehe";
133131
let key3 = "this is a key";
134132

135133
let val1 = "mock value";
136-
let val2 = "mock value 2";
134+
let val2 = "mock value mock data hehe";
137135
let val3 = "this is a new value";
138136

139137
let mut tx = db.transaction(true).unwrap();

db/src/storage/kvs/rocksdb/tx.rs

+16-10
Original file line numberDiff line numberDiff line change
@@ -278,20 +278,26 @@ impl SimpleTransaction for DBTransaction<DBType, TxType> {
278278
let guarded_tx = self.tx.lock().await;
279279
let tx = guarded_tx.as_ref().unwrap();
280280

281-
let iterator = match cf {
281+
let get_iterator = match cf {
282282
Some(_) => {
283-
let cf = &self.get_column_family(cf).unwrap();
284-
tx.iterator_cf(cf, IteratorMode::Start)
283+
let get_cf = self.get_column_family(cf);
284+
match get_cf {
285+
Ok(cf) => Ok(tx.iterator_cf(&cf, IteratorMode::Start)),
286+
Err(err) => Err(err),
287+
}
285288
}
286-
None => tx.iterator(IteratorMode::Start),
289+
None => Ok(tx.iterator(IteratorMode::Start)),
287290
};
288291

289-
Ok(iterator
290-
.map(|pair| {
291-
let (k, v) = pair.unwrap();
292-
Ok((k.to_vec(), v.to_vec()))
293-
})
294-
.collect())
292+
match get_iterator {
293+
Ok(iterator) => Ok(iterator
294+
.map(|pair| {
295+
let (k, v) = pair.unwrap();
296+
Ok((k.to_vec(), v.to_vec()))
297+
})
298+
.collect()),
299+
Err(err) => Err(err),
300+
}
295301
}
296302

297303
async fn suffix_iterate<S>(

db/src/util/byte.rs

-61
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,4 @@
1-
use std::io::{Cursor, Error as IoError, Write};
2-
3-
use byteorder::{BigEndian, WriteBytesExt};
4-
use chrono::{DateTime, NaiveDateTime, Timelike, Utc};
5-
6-
use lazy_static::lazy_static;
71
use rand::Rng;
8-
use uuid::Uuid;
9-
10-
lazy_static! {
11-
/// The maximum possible datetime.
12-
pub static ref MAX_DATETIME: DateTime<Utc> =
13-
DateTime::from_utc(NaiveDateTime::from_timestamp_opt(i64::from(i32::MAX), 0).unwrap(), Utc)
14-
.with_nanosecond(1_999_999_999u32)
15-
.unwrap();
16-
}
17-
18-
pub enum Component<'a> {
19-
Uuid(Uuid),
20-
FixedLengthString(&'a str),
21-
DateTime(DateTime<Utc>),
22-
Bytes(&'a [u8]),
23-
Usize(usize),
24-
}
25-
26-
impl<'a> Component<'a> {
27-
pub fn len(&self) -> usize {
28-
match *self {
29-
Component::Uuid(_) => 16,
30-
Component::FixedLengthString(s) => s.len(),
31-
Component::DateTime(_) => 8,
32-
Component::Bytes(b) => b.len(),
33-
Component::Usize(_) => 1,
34-
}
35-
}
36-
37-
pub fn write(&self, cursor: &mut Cursor<Vec<u8>>) -> Result<(), IoError> {
38-
match *self {
39-
Component::Uuid(uuid) => cursor.write_all(uuid.as_bytes()),
40-
Component::FixedLengthString(s) => cursor.write_all(s.as_bytes()),
41-
Component::DateTime(datetime) => {
42-
let time_to_end = nanos_since_epoch(&MAX_DATETIME) - nanos_since_epoch(&datetime);
43-
cursor.write_u64::<BigEndian>(time_to_end)
44-
}
45-
Component::Bytes(bytes) => cursor.write_all(bytes),
46-
Component::Usize(value) => cursor.write_all(&[value.try_into().unwrap()]),
47-
}
48-
}
49-
50-
pub fn _read_uuid(bytes: &[u8]) -> Result<Uuid, IoError> {
51-
let mut fix: [u8; 16] = Default::default();
52-
fix.copy_from_slice(&bytes[0..16]);
53-
Ok(Uuid::from_bytes(fix))
54-
}
55-
}
56-
57-
/// Gets the number of nanoseconds since unix epoch for a given datetime.
58-
fn nanos_since_epoch(datetime: &DateTime<Utc>) -> u64 {
59-
let timestamp = datetime.timestamp() as u64;
60-
let nanoseconds = u64::from(datetime.timestamp_subsec_nanos());
61-
timestamp * 1_000_000_000 + nanoseconds
62-
}
632

643
pub fn generate_random_i32() -> i32 {
654
let mut rng = rand::thread_rng();

gui/Cargo.toml

-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ tokio = { version = "1.11.0", features = ["full"] }
1515
edma_storage = { path = "../db", version = "*" }
1616
path-absolutize = "3.0.14"
1717
unicode-width = "0.1.10"
18-
easy-cast = "0.5.1"
1918
uuid = "1.2.2"
2019
tui-textarea = "0.2.0"
2120
structopt = "0.3.26"

gui/src/components/database/textarea.rs gui/src/components/database/command.rs

+65-17
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{
22
components::{render_container, RenderAbleComponent},
33
config::Config,
4-
constants::HIGHLIGHT_COLOR,
4+
constants::{BORDER_TYPE, HIGHLIGHT_COLOR},
55
events::{EventState, Key},
66
};
77
use anyhow::Result;
@@ -10,7 +10,7 @@ use tui::{
1010
layout::Rect,
1111
style::{Color, Modifier, Style},
1212
text::Text,
13-
widgets::Paragraph,
13+
widgets::{Block, Borders, Paragraph},
1414
Frame,
1515
};
1616
use tui_textarea::{Input, Key as InputKey, TextArea};
@@ -20,23 +20,62 @@ enum Focus {
2020
Textarea,
2121
}
2222

23-
pub struct TextareaComponent {
23+
#[derive(Clone, Debug)]
24+
pub struct Command {
25+
pub token: String,
26+
pub value: String,
27+
}
28+
29+
pub struct CommandComponent {
2430
config: Config,
2531
text: Vec<char>,
2632
focus: Focus,
33+
invalid: (bool, String),
34+
pub commands: Vec<Command>,
2735
}
2836

29-
impl TextareaComponent {
37+
impl CommandComponent {
3038
pub fn new(config: Config) -> Self {
31-
TextareaComponent {
39+
CommandComponent {
3240
config,
3341
text: vec![],
3442
focus: Focus::Container,
43+
invalid: (false, "".to_string()),
44+
commands: vec![],
3545
}
3646
}
3747

48+
fn set_invalid(&mut self, invalid: bool, err: &str) {
49+
self.invalid = (invalid, err.to_string());
50+
}
51+
52+
fn add_command(&mut self, command: Command) {
53+
self.commands.push(command);
54+
}
55+
3856
fn handle_command(&mut self) {
39-
unimplemented!()
57+
let mapped: Vec<_> = self.text.iter().map(|t| t.to_string()).collect();
58+
let complete = mapped.join("");
59+
let splitted = complete.split(' ');
60+
for token in splitted {
61+
match token {
62+
t if token.starts_with("COLUMN") | token.starts_with("TABLE") => {
63+
let value = t.split('=').nth(1);
64+
match value {
65+
Some(v) => self.add_command(Command {
66+
token: "COLUMN".to_string(),
67+
value: v.to_string(),
68+
}),
69+
None => {
70+
return self.set_invalid(true, "No COLUMN value found");
71+
}
72+
}
73+
}
74+
_ => return self.set_invalid(true, "Mismatch command"),
75+
}
76+
}
77+
78+
self.set_invalid(false, "");
4079
}
4180

4281
pub async fn event(&mut self, key: Key) -> Result<EventState> {
@@ -72,34 +111,43 @@ impl TextareaComponent {
72111
}
73112
}
74113

75-
impl RenderAbleComponent for TextareaComponent {
114+
impl RenderAbleComponent for CommandComponent {
76115
fn render<B: Backend>(
77116
&self,
78117
f: &mut Frame<B>,
79118
rect: Rect,
80119
focused: bool,
81120
) -> Result<(), anyhow::Error> {
121+
let keycode = match self.focus {
122+
Focus::Container => "ENTER",
123+
Focus::Textarea => "ESC",
124+
};
125+
let label = &format!("Command [{}]", keycode);
82126
if matches!(self.focus, Focus::Container) && self.text.is_empty() {
83127
let mut placeholder = Text::from("Press Enter to write a command");
84128
placeholder.patch_style(Style::default().fg(Color::DarkGray));
85129

86-
let keycode = match self.focus {
87-
Focus::Container => "ENTER",
88-
Focus::Textarea => "ESC",
89-
};
90-
let label = &format!("Command [{}]", keycode);
91130
let widget = Paragraph::new(placeholder).block(render_container(label, focused));
92131
f.render_widget(widget, rect);
93132
} else if matches!(self.focus, Focus::Textarea) || !self.text.is_empty() {
94133
let style = Style::default().bg(HIGHLIGHT_COLOR).add_modifier(Modifier::BOLD);
95134
let mut textarea = TextArea::default();
96135
textarea.set_cursor_style(style);
97-
let keycode = match self.focus {
98-
Focus::Container => "ENTER",
99-
Focus::Textarea => "ESC",
136+
137+
let (invalid, err) = &self.invalid;
138+
if *invalid {
139+
let label = &format!("{} [{}]", err, keycode);
140+
let container = Block::default()
141+
.borders(Borders::ALL)
142+
.style(Style::default().fg(Color::Red))
143+
.title(label.clone())
144+
.border_type(BORDER_TYPE);
145+
textarea.set_style(Style::default().fg(Color::Red));
146+
textarea.set_block(container);
147+
} else {
148+
let container = render_container(label, focused);
149+
textarea.set_block(container);
100150
};
101-
let label = &format!("Command [{}]", keycode);
102-
textarea.set_block(render_container(label, focused));
103151

104152
for c in self.text.iter() {
105153
textarea.input(Input {

0 commit comments

Comments
 (0)