show attributes of current database

This commit is contained in:
Emily Toop 2017-06-28 16:58:29 -07:00
parent a9c05ba9b7
commit 9932a98c6f
3 changed files with 72 additions and 4 deletions

View file

@ -38,6 +38,7 @@ pub static CLOSE_COMMAND: &'static str = &"close";
pub static LONG_QUERY_COMMAND: &'static str = &"query"; pub static LONG_QUERY_COMMAND: &'static str = &"query";
pub static SHORT_QUERY_COMMAND: &'static str = &"q"; pub static SHORT_QUERY_COMMAND: &'static str = &"q";
pub static SCHEMA_COMMAND: &'static str = &"schema"; pub static SCHEMA_COMMAND: &'static str = &"schema";
pub static ATTRIBUTES_COMMAND: &'static str = &"attributes";
pub static LONG_TRANSACT_COMMAND: &'static str = &"transact"; pub static LONG_TRANSACT_COMMAND: &'static str = &"transact";
pub static SHORT_TRANSACT_COMMAND: &'static str = &"t"; pub static SHORT_TRANSACT_COMMAND: &'static str = &"t";
pub static LONG_EXIT_COMMAND: &'static str = &"exit"; pub static LONG_EXIT_COMMAND: &'static str = &"exit";
@ -51,6 +52,7 @@ pub enum Command {
Open(String), Open(String),
Query(String), Query(String),
Schema, Schema,
Attributes,
Transact(String), Transact(String),
} }
@ -69,7 +71,8 @@ impl Command {
&Command::Open(_) | &Command::Open(_) |
&Command::Close | &Command::Close |
&Command::Exit | &Command::Exit |
&Command::Schema => true &Command::Schema |
&Command::Attributes => true
} }
} }
@ -96,6 +99,9 @@ impl Command {
&Command::Schema => { &Command::Schema => {
format!(".{}", SCHEMA_COMMAND) format!(".{}", SCHEMA_COMMAND)
}, },
&Command::Attributes => {
format!(".{}", ATTRIBUTES_COMMAND)
},
} }
} }
} }
@ -144,6 +150,15 @@ pub fn command(s: &str) -> Result<Command, cli::Error> {
} }
Ok(Command::Schema) Ok(Command::Schema)
}); });
let attributes_parser = string(ATTRIBUTES_COMMAND)
.with(no_arg_parser())
.map(|args| {
if !args.is_empty() {
bail!(cli::ErrorKind::CommandParse(format!("Unrecognized argument {:?}", args[0])) );
}
Ok(Command::Attributes)
});
let exit_parser = try(string(LONG_EXIT_COMMAND)).or(try(string(SHORT_EXIT_COMMAND))) let exit_parser = try(string(LONG_EXIT_COMMAND)).or(try(string(SHORT_EXIT_COMMAND)))
.with(no_arg_parser()) .with(no_arg_parser())
@ -176,13 +191,14 @@ pub fn command(s: &str) -> Result<Command, cli::Error> {
spaces() spaces()
.skip(token('.')) .skip(token('.'))
.with(choice::<[&mut Parser<Input = _, Output = Result<Command, cli::Error>>; 7], _> .with(choice::<[&mut Parser<Input = _, Output = Result<Command, cli::Error>>; 8], _>
([&mut try(help_parser), ([&mut try(help_parser),
&mut try(open_parser), &mut try(open_parser),
&mut try(close_parser), &mut try(close_parser),
&mut try(exit_parser), &mut try(exit_parser),
&mut try(query_parser), &mut try(query_parser),
&mut try(schema_parser), &mut try(schema_parser),
&mut try(attributes_parser),
&mut try(transact_parser)])) &mut try(transact_parser)]))
.parse(s) .parse(s)
.unwrap_or((Err(cli::ErrorKind::CommandParse(format!("Invalid command {:?}", s)).into()), "")).0 .unwrap_or((Err(cli::ErrorKind::CommandParse(format!("Invalid command {:?}", s)).into()), "")).0
@ -390,6 +406,33 @@ mod tests {
} }
} }
#[test]
fn test_attributes_parser_with_args() {
let input = ".attributes arg1";
let err = command(&input).expect_err("Expected an error");
assert_eq!(err.to_string(), format!("Invalid command {:?}", input));
}
#[test]
fn test_attributes_parser_no_args() {
let input = ".attributes";
let cmd = command(&input).expect("Expected attributes command");
match cmd {
Command::Attributes => assert!(true),
_ => assert!(false)
}
}
#[test]
fn test_attributes_parser_no_args_trailing_whitespace() {
let input = ".attributes ";
let cmd = command(&input).expect("Expected attributes command");
match cmd {
Command::Attributes => assert!(true),
_ => assert!(false)
}
}
#[test] #[test]
fn test_query_parser_complete_edn() { fn test_query_parser_complete_edn() {
let input = ".q [:find ?x :where [?x foo/bar ?y]]"; let input = ".q [:find ?x :where [?x foo/bar ?y]]";

View file

@ -27,6 +27,7 @@ use command_parser::{
SHORT_TRANSACT_COMMAND, SHORT_TRANSACT_COMMAND,
LONG_EXIT_COMMAND, LONG_EXIT_COMMAND,
SHORT_EXIT_COMMAND, SHORT_EXIT_COMMAND,
ATTRIBUTES_COMMAND,
}; };
use input::InputReader; use input::InputReader;
use input::InputResult::{ use input::InputResult::{
@ -43,6 +44,7 @@ use store::{
lazy_static! { lazy_static! {
static ref COMMAND_HELP: HashMap<&'static str, &'static str> = { static ref COMMAND_HELP: HashMap<&'static str, &'static str> = {
let mut map = HashMap::new(); let mut map = HashMap::new();
map.insert(ATTRIBUTES_COMMAND, "Output the attributes for the schema in the current open database.");
map.insert(LONG_EXIT_COMMAND, "Close the current database and exit the REPL."); map.insert(LONG_EXIT_COMMAND, "Close the current database and exit the REPL.");
map.insert(SHORT_EXIT_COMMAND, "Shortcut for `.exit`. Close the current database and exit the REPL."); map.insert(SHORT_EXIT_COMMAND, "Shortcut for `.exit`. Close the current database and exit the REPL.");
map.insert(HELP_COMMAND, "Show help for commands."); map.insert(HELP_COMMAND, "Show help for commands.");
@ -120,8 +122,14 @@ impl Repl {
Ok(s) => println!("{}", s), Ok(s) => println!("{}", s),
Err(e) => println!("{}", e) Err(e) => println!("{}", e)
}; };
},
} Command::Attributes => {
let edn = self.store.fetch_attributes();
match edn.to_pretty(120) {
Ok(s) => println!("{}", s),
Err(e) => println!("{}", e)
};
},
Command::Transact(transaction) => self.execute_transact(transaction), Command::Transact(transaction) => self.execute_transact(transaction),
Command::Exit => { Command::Exit => {
self.close(); self.close();

View file

@ -62,7 +62,24 @@ impl Store {
Ok(self.conn.transact(&mut self.handle, &transaction)?) Ok(self.conn.transact(&mut self.handle, &transaction)?)
} }
// the schema is the entire schema of the store including structure used to describe the store.
pub fn fetch_schema(&self) -> edn::Value { pub fn fetch_schema(&self) -> edn::Value {
self.conn.current_schema().to_edn_value() self.conn.current_schema().to_edn_value()
} }
// the attributes are the specific attributes added to the schema for this particular store.
pub fn fetch_attributes(&self) -> edn::Value {
let schema = self.conn.current_schema();
edn::Value::Vector((&schema.schema_map).iter()
.filter_map(|(entid, attribute)| {
if let Some(ident) = schema.get_ident(*entid) {
if !ident.namespace.starts_with("db") {
return Some(attribute.to_edn_value(Some(ident.clone())));
}
}
return None;
})
.collect())
}
} }