Skip to content
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

json: add error for empty key and update usage text #2167

Merged
merged 2 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
18 changes: 14 additions & 4 deletions src/cmd/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ Convert JSON to CSV.
The JSON data is expected to be non-empty and non-nested as either:

1. An array of objects where:
A. All objects are non-empty and have the same keys.
A. All objects are non-empty, have non-empty and unique keys, and the same keys are in each object.
B. Values are not objects or arrays.
2. An object where values are not objects or arrays.
2. An object where values are not objects or arrays and the object is as described above.

Objects with duplicate keys are not recommended as only one key and its values may be used.

If your JSON data is not in the expected format and/or is nested or complex, try using
the --jaq option to pass a jq-like filter before parsing with the above constraints.
Expand Down Expand Up @@ -80,8 +82,8 @@ json options:
which is identical to the popular JSON command-line tool - jq.
https://jqlang.github.io/jq/
Note that the filter is applied BEFORE converting JSON to CSV
-s, --select <cols> Select, reorder or drop columns for output.
Otherwise, all the columns will be output in the same order as
-s, --select <cols> Select, reorder or drop columns for output.
Otherwise, all the columns will be output in the same order as
the first object's keys in the JSON data.
See 'qsv select --help' for the full syntax.
Note however that <cols> NEED to be a comma-delimited list
Expand Down Expand Up @@ -218,6 +220,14 @@ pub fn run(argv: &[&str]) -> CliResult<()> {
}
let mut first_dict_headers: Vec<&str> = Vec::new();
for key in first_dict.keys() {
if key.is_empty() {
return Err(CliError::Other("Expected a non-empty JSON key".to_string()));
}
if first_dict_headers.contains(&key.as_str()) {
return Err(CliError::Other(format!(
"Expected non-duplicate keys, found key: {key}"
)));
}
first_dict_headers.push(key.as_str());
}

Expand Down
47 changes: 47 additions & 0 deletions tests/test_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,3 +328,50 @@ fn json_nested() {

assert_eq!(got, expected);
}

#[test]
#[serial]
fn json_empty_keys_with_jaq() {
let wrk = Workdir::new("json_empty_keys_with_jaq");
let json_data = serde_json::json!({
"data": [
{
"fruit": "apple",
"": 0.50
},
{
"fruit": "banana",
"": 1.00
}
]
});
let filter = ".data";

wrk.create_from_string("data.json", json_data.to_string().as_str());
let mut cmd = wrk.command("json");
cmd.arg("data.json");
cmd.args(vec!["--jaq", filter]);

wrk.assert_err(&mut cmd);
}

#[test]
#[serial]
fn json_empty_keys() {
let wrk = Workdir::new("json_empty_keys");
let json_data = serde_json::json!([
{
"fruit": "apple",
"": 0.50
},
{
"fruit": "banana",
"": 1.00
}
]);
wrk.create_from_string("data.json", json_data.to_string().as_str());
let mut cmd = wrk.command("json");
cmd.arg("data.json");

wrk.assert_err(&mut cmd);
}
Loading