-
Notifications
You must be signed in to change notification settings - Fork 110
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cli client #157
Cli client #157
Conversation
client/src/main.rs
Outdated
@@ -160,9 +163,11 @@ pub async fn main() -> Result<(), Box<dyn Error>> { | |||
.get_matches(); | |||
|
|||
let _address = matches.value_of("address").unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be renamed to address
. Some of the variables in here were prefixed with an underscore temporarily to pass clippy, until they're used.
client/src/main.rs
Outdated
|
||
if let Some(_matches) = matches.subcommand_matches("ping") { | ||
unimplemented!(); | ||
client.ping().await.map_err(|err| err.compat())?; | ||
println!("PING OK"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's just print ok
.
} | ||
|
||
panic!("unknown command"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If match fails on any of the nested ifs, a panic won't occur with this change. A couple of options here:
-
Add the panic to each of the nested if arms.
-
Keep the old panic, but call into a function on any of the if arms. e.g.:
if let Some(_matches) = matches.subcommand_matches("ping") {
return ping(client).await;
} ...
As more code gets added, (2) will probably be cleaner.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it.
I also found a setting for the App/Subcommand which enforces that at least one of the subcommands must be used.
I think this will error out more gracefully than panicking manually.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have pushed a few more changes.
If match fails on any of the nested ifs, a panic won't occur with this change.
By enforcing that "at least one" of the nested subcommands is used at runtime (using AppSettings::SubcommandRequiredElseHelp
), we should not run into this condition
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh cool, nice find!
client/src/main.rs
Outdated
} else if let Some(matches) = matches.subcommand_matches("set") { | ||
if let Some(_matches) = matches.subcommand_matches("vertex") { | ||
unimplemented!(); | ||
let link_type = indradb::Type::new(_matches.value_of("type").unwrap()).map_err(|err| err.compat())?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would more appropriately be called vertex_type
client/src/main.rs
Outdated
|
||
if let Some(_matches) = matches.subcommand_matches("ping") { | ||
unimplemented!(); | ||
client.ping().await.map_err(|err| err.compat())?; | ||
println!("ok"); | ||
} else if let Some(matches) = matches.subcommand_matches("set") { | ||
if let Some(_matches) = matches.subcommand_matches("vertex") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The underscore prefix for this can be removed now
client/src/main.rs
Outdated
.await.map_err(|err| err.compat())? | ||
.create_vertex(&vertex) | ||
.await.map_err(|err| err.compat())?; | ||
if res == false { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be simplified to if !res {
client/src/main.rs
Outdated
.create_vertex(&vertex) | ||
.await.map_err(|err| err.compat())?; | ||
if res == false { | ||
panic!("Failed to create vertex with id: {} and type: {}", vertex.id, vertex.t.0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should return a new error rather than panicking
client/src/main.rs
Outdated
if res == false { | ||
panic!("Failed to create vertex with id: {} and type: {}", vertex.id, vertex.t.0); | ||
} | ||
println!("Created vertex with id: {} and type: {}", vertex.id, vertex.t.0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe just print the debug version of the vertex (i.e., println!("{:?}", vertex);
), that way it should be easier to parse if this is used in a script
For setting vertex properties, we expect the vertex query as a JSON.
|
In a separate PR, I'll make VertexQuery and EdgeQuery auto-derive For deserializing to a straight-up JSON value, you should similarly be able to do something like |
Instead of supporting full-blown vertex/edge queries, let's just support operations on individual vertices (by UUID) / edges (by edge key.) That'll make things a lot easier, and still deliver a good amount of value. |
Since we're now only supporting vertex queries by |
There is still some marginal utility, in that you’d get back info on whether the vertex/edge exists, as well as it’s update time stamp. But yeah it’s pretty limited, and not needed for initial version of the client. |
Got it. In that case ill just implement it, doesnt seem like too much effort |
Signed-off-by: binoychitale <binoychitale@gmail.com>
Signed-off-by: binoychitale <binoychitale@gmail.com>
Signed-off-by: binoychitale <binoychitale@gmail.com>
Signed-off-by: binoychitale <binoychitale@gmail.com>
Signed-off-by: binoychitale <binoychitale@gmail.com>
Signed-off-by: binoychitale <binoychitale@gmail.com>
Signed-off-by: binoychitale <binoychitale@gmail.com>
Signed-off-by: binoychitale <binoychitale@gmail.com>
Signed-off-by: binoychitale <binoychitale@gmail.com>
Signed-off-by: binoychitale <binoychitale@gmail.com>
Signed-off-by: binoychitale <binoychitale@gmail.com>
dc27244
to
2167549
Compare
let edge_type_arg = Arg::with_name("type").help("the edge type").required(true); | ||
let inbound_id_arg = Arg::with_name("inbound_id") | ||
.help("the inbound vertex ID") | ||
.required(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do these args require either a .takes_value(true)
or .index(true)
? Maybe they don't, not sure.
lib/src/errors.rs
Outdated
@@ -17,6 +17,8 @@ pub enum Error { | |||
Sled { inner: SledError }, | |||
#[fail(display = "UUID already taken")] | |||
UuidTaken, | |||
#[fail(display = "Invalid vertex")] | |||
VertexInvalid, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be a separate error in the bin crate, since it's not produced in lib ever. Thankfully, because main
returns Box<dyn Error>
, different types of errors can be returned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct me if wrong here but I think this actually would be useful in lib, because if create_edge
returns a false
from a non-CLI call, it would still be useful error to throw. (maybe pave the way to return an error instead of a boolean value from this method in the future)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the library level, it's not considered an error to insert a redundant vertex. This has a couple of distinct advantages:
- For datastores that provide all-or-none transaction semantics, inserting a vertex redundantly won't invalidate the entire transaction.
- Similarly, for bulk inserts, this ensures that an attempt to create a vertex won't invalidate the entire bulk insert operation.
Some(_) => indradb::EdgeDirection::Inbound, | ||
None => indradb::EdgeDirection::Outbound, | ||
}; | ||
let edge_type = match matches.value_of("type") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use Option::map
to simplify this a bit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure how to cleanly bubble errors out of the closure without making the code equally verbose
For e.g if I write -
let edge_type = matches.value_of("type")
.map(|edge_type| indradb::Type::new(edge_type).map_err(|err| err.compat()));
the error thrown by the new()
method needs to be handled in the outer function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah right, yeah a match seems like the right move here
|
||
if let Some(_matches) = matches.subcommand_matches("ping") { | ||
unimplemented!(); | ||
println!("ok"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the only command that doesn't acquire a transaction, so to shorten the code, it might be good to restructure to something like this:
if matches.subcommand_matches("ping").is_some() {
// ...ping
return Ok(());
}
let trans = client.transaction().await.map_err(|err| err.compat())?;
// ...various subcommand matches here
.help("the JSON edge query") | ||
.required(true) | ||
.index(1); | ||
let edge_query_arg = [outbound_id_arg, edge_type_arg, inbound_id_arg]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This + the various build functions are a nice way to shorten the code 👍
Signed-off-by: binoychitale <binoychitale@gmail.com>
Signed-off-by: binoychitale <binoychitale@gmail.com>
Signed-off-by: binoychitale <binoychitale@gmail.com>
This looks almost ready to merge! Could you take a look at the warnings triggered by github actions in the diff? Once that's done, I'll take a final pass. |
Signed-off-by: binoychitale <binoychitale@gmail.com>
I've resolved the clippy warnings, we're good to go :) |
The CLI client just went out in the latest release (v2.1.0), and is available on linux/macos as a pre-built binary. Congrats and thanks again for this substantial contribution, @binoychitale! |
Signed-off-by: binoychitale binoychitale@gmail.com
Fixes #141