Skip to content
This repository has been archived by the owner on Aug 3, 2023. It is now read-only.

Add key listing functionality for workers kv subcommands #462

Merged
merged 8 commits into from
Aug 22, 2019
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

94 changes: 94 additions & 0 deletions src/commands/kv/list_keys.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
extern crate serde_json;

use cloudflare::endpoints::workerskv::list_namespace_keys::ListNamespaceKeys;
use cloudflare::endpoints::workerskv::list_namespace_keys::ListNamespaceKeysParams;
use cloudflare::endpoints::workerskv::Key;
use cloudflare::framework::apiclient::ApiClient;
use failure::bail;
use serde_json::value::Value as JsonValue;

// Note: this function only prints keys in json form, given that
// the number of entries in each json blob is variable (so csv and tsv
// representation won't make sense)
pub fn list_keys(id: &str, prefix: Option<&str>) -> Result<(), failure::Error> {
let client = super::api_client()?;
let account_id = super::account_id()?;

let params = ListNamespaceKeysParams {
limit: None, // Defaults to 1000 (the maximum)
cursor: None,
prefix: prefix.map(str::to_string),
gabbifish marked this conversation as resolved.
Show resolved Hide resolved
};

let mut request_params = ListNamespaceKeys {
account_identifier: &account_id,
namespace_identifier: id,
params: params,
};

let mut response = client.request(&request_params);

print!("["); // Open json list bracket

// Iterate over all pages until no pages of keys are left.
// This is detected when a returned cursor is an empty string.
// todo(gabbi): the code in this loop is the product of a looooong fight
gabbifish marked this conversation as resolved.
Show resolved Hide resolved
// with the borrow checker. Please tell me if there's a neater way to write
// the logic below!
loop {
let (result, cursor) = match response {
Ok(success) => (
success.result,
get_cursor_from_result_info(success.result_info.clone()),
),
Err(e) => bail!(e),
};

match cursor {
None => {
// Case where we are done iterating through pages (no cursor returned)
print_page(result, true)?;
print!("]"); // Close json list bracket
break;
}
Some(_) => {
// Case where we still have pages to iterate through (a cursor is returned).
// Update cursor in request_params.params, and make another request to Workers KV API.
request_params.params.cursor = cursor;

// todo(gabbi): Right now, I print out the results of every page
gabbifish marked this conversation as resolved.
Show resolved Hide resolved
// as wrangler gets them (instead of storing them in memory and
// outputting them all at once). What do the reviewers think about this?
// I figured this was the best option because it wouldn't eat memory, but
// I'm curious what other folks think.
print_page(result, false)?;
response = client.request(&request_params);
}
}
}

Ok(())
}

// Returns Some(cursor) if cursor is non-empty, otherwise returns None.
fn get_cursor_from_result_info(result_info: Option<JsonValue>) -> Option<String> {
let result_info = result_info.unwrap();
let returned_cursor_value = &result_info["cursor"];
let returned_cursor = returned_cursor_value.as_str().unwrap().to_string();
if returned_cursor.is_empty() {
None
} else {
Some(returned_cursor)
}
}

fn print_page(keys: Vec<Key>, last_page: bool) -> Result<(), failure::Error> {
for i in 0..keys.len() {
print!("{}", serde_json::to_string(&keys[i])?);
// if last key on last page, don't print final comma.
if !(last_page && i == keys.len() - 1) {
print!(",");
}
}
Ok(())
}
2 changes: 2 additions & 0 deletions src/commands/kv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ mod create_namespace;
mod delete_bulk;
mod delete_key;
mod delete_namespace;
mod list_keys;
mod list_namespaces;
mod read_key;
mod rename_namespace;
Expand All @@ -22,6 +23,7 @@ pub use create_namespace::create_namespace;
pub use delete_bulk::delete_bulk;
pub use delete_key::delete_key;
pub use delete_namespace::delete_namespace;
pub use list_keys::list_keys;
pub use list_namespaces::list_namespaces;
pub use read_key::read_key;
pub use rename_namespace::rename_namespace;
Expand Down
19 changes: 19 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,20 @@ fn run() -> Result<(), failure::Error> {
Arg::with_name("path")
)
)
.subcommand(
SubCommand::with_name("list-keys")
.arg(
Arg::with_name("id")
)
.arg(
Arg::with_name("prefix")
.short("p")
.long("prefix")
.value_name("STRING")
.takes_value(true)
.help("The prefix to filter listed keys by"),
)
)
)
.subcommand(
SubCommand::with_name("generate")
Expand Down Expand Up @@ -411,6 +425,11 @@ fn run() -> Result<(), failure::Error> {
let path = delete_matches.value_of("path").unwrap();
commands::kv::delete_bulk(id, Path::new(path))?;
}
("list-keys", Some(list_keys_matches)) => {
let id = list_keys_matches.value_of("id").unwrap();
let prefix = list_keys_matches.value_of("prefix");
commands::kv::list_keys(id, prefix)?;
}
("", None) => message::warn("kv expects a subcommand"),
_ => unreachable!(),
}
Expand Down