New --collection flag to json_parse command which returns maps/arrays instead of variables #175

This commit is contained in:
sagie gur ari 2021-07-09 15:52:33 +00:00
parent dd760cfb50
commit 540e556908
6 changed files with 144 additions and 12 deletions

View file

@ -1,5 +1,9 @@
## CHANGELOG
### v0.8.4
* New --collection flag to json_parse command which returns maps/arrays instead of variables #175
### v0.8.3
* Fix release with recursive flag to support set data structures as well.

View file

@ -4142,17 +4142,22 @@ root.child[5]
root.child.length
```
In case the --collection flag is provided, it will instead create maps/array as needed and return the root handle (or primitive value) of
the json data.
#### Parameters
The JSON string to parse.
* Optional --collection flag to parse and return value/map/array
* The JSON string to parse.
#### Return Value
The root value.
The root value/handle.
#### Examples
```sh
# parse to simple variables
package = json_parse "{\"name\": \"my package\", \"version\": 1, \"publish\": false, \"keywords\": [\"test1\", \"test2\"], \"directories\": {\"test\": \"spec\"}}"
assert_eq ${package} "[OBJECT]"
@ -4163,6 +4168,25 @@ assert_eq ${package.keywords.length} 2
assert_eq ${package.keywords[0]} test1
assert_eq ${package.keywords[1]} test2
assert_eq ${package.directories.test} spec
# parse to maps/arrays
package = json_parse --collection "{\"name\": \"my package\", \"version\": 1, \"publish\": false, \"keywords\": [\"test1\", \"test2\"], \"directories\": {\"test\": \"spec\"}}"
name = map_get ${package} name
assert_eq ${name} "my package"
version = map_get ${package} version
assert_eq ${version} 1
public = map_get ${package} public
assert_false ${public}
keywords_handle = map_get ${package} keywords
length = array_length ${keywords_handle}
assert_eq ${length} 2
value = array_pop ${keywords_handle}
assert_eq ${value} test2
value = array_pop ${keywords_handle}
assert_eq ${value} test1
directories = map_get ${package} directories
directory = map_get ${directories} test
assert_eq ${directory} spec
```

View file

@ -12,17 +12,22 @@ root.child[5]
root.child.length
```
In case the --collection flag is provided, it will instead create maps/array as needed and return the root handle (or primitive value) of
the json data.
#### Parameters
The JSON string to parse.
* Optional --collection flag to parse and return value/map/array
* The JSON string to parse.
#### Return Value
The root value.
The root value/handle.
#### Examples
```sh
# parse to simple variables
package = json_parse "{\"name\": \"my package\", \"version\": 1, \"publish\": false, \"keywords\": [\"test1\", \"test2\"], \"directories\": {\"test\": \"spec\"}}"
assert_eq ${package} "[OBJECT]"
@ -33,4 +38,23 @@ assert_eq ${package.keywords.length} 2
assert_eq ${package.keywords[0]} test1
assert_eq ${package.keywords[1]} test2
assert_eq ${package.directories.test} spec
# parse to maps/arrays
package = json_parse --collection "{\"name\": \"my package\", \"version\": 1, \"publish\": false, \"keywords\": [\"test1\", \"test2\"], \"directories\": {\"test\": \"spec\"}}"
name = map_get ${package} name
assert_eq ${name} "my package"
version = map_get ${package} version
assert_eq ${version} 1
public = map_get ${package} public
assert_false ${public}
keywords_handle = map_get ${package} keywords
length = array_length ${keywords_handle}
assert_eq ${length} 2
value = array_pop ${keywords_handle}
assert_eq ${value} test2
value = array_pop ${keywords_handle}
assert_eq ${value} test1
directories = map_get ${package} directories
directory = map_get ${directories} test
assert_eq ${directory} spec
```

View file

@ -1,5 +1,6 @@
use crate::sdk::std::json::OBJECT_VALUE;
use crate::utils::pckg;
use crate::utils::state::put_handle;
use duckscript::types::command::{Command, CommandResult, Commands};
use duckscript::types::instruction::Instruction;
use duckscript::types::runtime::StateValue;
@ -46,6 +47,41 @@ fn create_variables(data: Value, name: &str, variables: &mut HashMap<String, Str
};
}
fn create_structure(data: Value, state: &mut HashMap<String, StateValue>) -> Option<String> {
match data {
Value::Null => None,
Value::Bool(value) => Some(value.to_string()),
Value::Number(value) => Some(value.to_string()),
Value::String(value) => Some(value),
Value::Array(list) => {
let mut state_list = vec![];
for item in list {
if let Some(value) = create_structure(item, state) {
state_list.push(StateValue::String(value));
}
}
let key = put_handle(state, StateValue::List(state_list));
Some(key)
}
Value::Object(map) => {
let mut state_map = HashMap::new();
for (key, value) in map {
if let Some(value) = create_structure(value, state) {
state_map.insert(key, StateValue::String(value));
}
}
let key = put_handle(state, StateValue::SubState(state_map));
Some(key)
}
}
}
#[derive(Clone)]
pub(crate) struct CommandImpl {
package: String,
@ -75,7 +111,7 @@ impl Command for CommandImpl {
fn run_with_context(
&self,
arguments: Vec<String>,
_state: &mut HashMap<String, StateValue>,
state: &mut HashMap<String, StateValue>,
variables: &mut HashMap<String, String>,
output_variable: Option<String>,
_instructions: &Vec<Instruction>,
@ -85,15 +121,25 @@ impl Command for CommandImpl {
if arguments.is_empty() {
CommandResult::Error("No JSON string provided.".to_string())
} else {
match parse_json(&arguments[0]) {
let (json_index, as_state) = if arguments.len() > 1 && arguments[0] == "--collection" {
(1, true)
} else {
(0, false)
};
match parse_json(&arguments[json_index]) {
Ok(data) => {
let output = match output_variable {
Some(name) => {
create_variables(data, &name, variables);
if as_state {
create_structure(data, state)
} else {
create_variables(data, &name, variables);
match variables.get(&name) {
Some(value) => Some(value.to_string()),
None => None,
match variables.get(&name) {
Some(value) => Some(value.to_string()),
None => None,
}
}
}
None => Some("true".to_string()),

View file

@ -13,7 +13,7 @@ fn run_no_args() {
}
#[test]
fn run_all_types() {
fn run_all_types_as_vars() {
let context = test::run_script_and_validate(
vec![create("")],
r#"

View file

@ -1,5 +1,5 @@
fn test_all_types
fn test_all_types_as_vars
package = json_parse "{\"name\": \"my package\", \"version\": 1, \"publish\": false, \"keywords\": [\"test1\", \"test2\"], \"directories\": {\"test\": \"spec\"}}"
assert_eq ${package} "[OBJECT]"
@ -12,3 +12,37 @@ fn test_all_types
assert_eq ${package.directories.test} spec
end
fn test_all_types_as_collections
package = json_parse --collection "{\"name\": \"my package\", \"version\": 1, \"publish\": false, \"keywords\": [\"test1\", \"test2\"], \"directories\": {\"test\": \"spec\"}}"
output = is_map ${package}
assert ${output}
name = map_get ${package} name
assert_eq ${name} "my package"
version = map_get ${package} version
assert_eq ${version} 1
public = map_get ${package} public
assert_false ${public}
keywords_handle = map_get ${package} keywords
output = is_array ${keywords_handle}
assert ${output}
length = array_length ${keywords_handle}
assert_eq ${length} 2
value = array_pop ${keywords_handle}
assert_eq ${value} test2
value = array_pop ${keywords_handle}
assert_eq ${value} test1
directories = map_get ${package} directories
output = is_map ${directories}
assert ${output}
directory = map_get ${directories} test
assert_eq ${directory} spec
end