Skip to content

Commit f8dea08

Browse files
committed
feat: Add to_json and from_json functions
JEP for adding to_json and from_json functions Closes: #8
1 parent 2d23153 commit f8dea08

1 file changed

Lines changed: 141 additions & 0 deletions

File tree

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# Title of the feature
2+
3+
- JEP: (leave blank)
4+
- Author: tmccombs
5+
- Created: 2023-05-30
6+
7+
## Abstract
8+
[abstract]: #abstract
9+
10+
Add two new functions which allow parsing a string into a JSON value, and serializing a value to a JSON string.
11+
12+
## Motivation
13+
[motivation]: #motivation
14+
15+
JSON values sometimes contain strings, which are themselves JSON. As a specific example, some AWS APIs
16+
return responses that include values which are strings containing JSON strings, such as IAM policy
17+
documents.
18+
19+
Previously, it was not possible to extract data from such a string directly with JMESPath. At least without
20+
having to use one pass to extract the string value, then use a different expression the result of parsing the
21+
JSON from that string.
22+
23+
Conversely, if you need to serialize data into a string field of the result, then if your input is not a string
24+
you can currently use `to_string`, but that function won't correctly serialize an existing string as a JSON string.
25+
If you don't know the actual type of the value, and it could be a string, you can't safely serialize as a JSON string.
26+
27+
## Specification
28+
[specification]: #specification
29+
30+
This JEP defines two new functions `from_json` and `to_json`.
31+
32+
### `from_json`
33+
34+
The `from_json` function has the following signature:
35+
36+
```
37+
any from_json(string $json_data)
38+
```
39+
40+
This function takes a string, and will parse it as a JSON document and return the resulting value. The resulting
41+
value may be any JSON type.
42+
43+
If the input string is not a valid JSON document, an `invalid-value` error is raised.
44+
45+
### `to_json`
46+
47+
The `to_json` function has the following signature:
48+
49+
```
50+
string to_json(any $value)
51+
```
52+
53+
This function performs the inverse of `from_json`. It takes any JSON value as input, and serialize the result
54+
as a JSON document, and then returns a string containing that serialized result. The resulting JSON should not
55+
contain any unneeded whitespace, including newlines, spaces, or tabs.
56+
57+
## Rationale
58+
[rationale]: #rationale
59+
60+
The names `from_json` and `to_json` were chosen because the names are symmetric with each other and are similar to
61+
the names of the corresponding functions in [`jq`](https://jqlang.github.io/jq/manual/#Convertto/fromJSON).
62+
63+
However, other names could also be accptable, such as:
64+
* `parse_json`/`stringify_json`
65+
* `json_parse`/`json_stringify`
66+
* `deserialize`/`serialize`
67+
68+
Another alternative is to add the `from_json` function but not the `to_json` function, since the existing
69+
`to_string` function can already serialize most values as json. However, the fact that it can't serialize a string as to
70+
JSON is an unfortunate gap, and it seems odd not to have symmetric functions going in both directions. If only a deserizalization
71+
function is added, `from_string` may also be an appropriate name.
72+
73+
This specification only supports serializing as minimal JSON without whitespace. This is conjectured to be what is desired in most
74+
cases where the `to_json` function is used, in order to keep the size of the resulting data small. This is also consistent
75+
with the existing `to_string` function. However, a future extension could
76+
provide functionality to output JSON in a "pretty" format including newlines and indentation, either as an additional function, or with
77+
an optional argument to the `to_json` function. However, this was intentionally left out of scope for this proposal to keep the scope small.
78+
79+
For handlinge invalid JSON input, another possibility is that `from_json` could return some kind of value. However, it would be difficult to distinguish
80+
between parsing a legitimate value, and inability to parse the string. And in most use cases, invalid JSON is probably an unexpected scenario that should
81+
be treated as an error.
82+
83+
## Testcases
84+
[testcases]: #testcases
85+
86+
```yaml
87+
given:
88+
string: "abc"
89+
empty_list: []
90+
empty_hash: {}
91+
object:
92+
foo: "bar"
93+
bar: "baz"
94+
'null': null
95+
json: |
96+
{
97+
"str": "string",
98+
"num": 1.25e4,
99+
"arr": [1,2, "a"],
100+
"nothing": null
101+
}
102+
cases:
103+
- expression: from_json(json)
104+
result:
105+
str: "string"
106+
num: 1.25e4
107+
arr: [1,2, "a"]
108+
nothing: null
109+
- expression: from_json(json).str
110+
result: "string"
111+
- expression: "from_json('true')"
112+
result: true
113+
- expression: "from_json('false')"
114+
result: false
115+
- expression: "from_json('123')"
116+
result: 123
117+
- expression: "from_json('1.5')"
118+
result: 1.5
119+
- expression: "from_json('1e8')"
120+
result: 1e8
121+
- expression: "from_json('5e-3')"
122+
result: .005
123+
- expression: "from_json('\"abc\"')"
124+
result: "abc"
125+
- expression: "from_json('[]'"
126+
result: []
127+
- expression: "from_json('{}')"
128+
result: {}
129+
- expression: "from_json('null')"
130+
result: null
131+
- expression: "from_json('abc')"
132+
error: invalid-value
133+
- expression: to_json(object)
134+
result: '{"foo":"bar","bar":"baz"}'
135+
- expression: to_json(string)
136+
result: '"abc"'
137+
- expression: to_json(empty_list)
138+
result: []
139+
- expression: to_json(empty_hash)
140+
result: {}
141+
```

0 commit comments

Comments
 (0)