Skip to content

Commit 0193cad

Browse files
authored
Merge pull request #617 from nmaludy/feature/json-jinja-filters
Implement new JSON Jinja filters
2 parents c8ad4ae + 468d154 commit 0193cad

2 files changed

Lines changed: 131 additions & 31 deletions

File tree

docs/source/datastore.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ Key-Value pairs can also have a TTL associated with them, for automatic expiry.
1919
simple and fully compatible with existing API and CLI commands.
2020

2121
If you want to store a non-string value, you can store a JSON-serialized version, and then
22-
de-serialize it in your action/sensor code.
22+
de-serialize it in your action/sensor code, or using the ``from_json_string``
23+
Jinja filter. See the :doc:`/reference/jinja` documentation for more details.
2324

2425
This may change in future if there is sufficient interest.
2526

docs/source/reference/jinja.rst

Lines changed: 129 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,29 @@ with Jinja in the context of |st2|. Please refer to the `Jinja docs
1212
Referencing Datastore Keys in Jinja
1313
------------------------------------
1414

15-
You can use ``{{st2kv.system.foo}}`` to access key ``foo`` from datastore. Note that until
16-
v2.1, the expression to access key ``foo`` from datastore used to be ``{{system.foo}}``
15+
You can use ``{{ st2kv.system.foo }}`` to access key ``foo`` from datastore. Note that until
16+
v2.1, the expression to access key ``foo`` from datastore used to be ``{{ system.foo }}``
1717
but is now deprecated, and the leading ``st2kv.`` namespace is required.
1818

19+
Currently, all data in the datastore is represented as strings. To represent
20+
complext data structures like ``dicts`` and ``lists`` the standard approach is to
21+
convert the data structure into JSON when storing the data, then parse it when
22+
retrieving the data.
23+
24+
.. code-block:: bash
25+
26+
# Pass the result of this expression to the action st2.kv.set
27+
{{ {'complex': 'structure', 'foo': ['x', True]} | to_json_string }}
28+
29+
# Read the data back in using the st2kv and from_json_string filters
30+
{{ st2kv.system.foo | from_json_string }}
31+
1932
.. _jinja-jinja-filters:
2033

2134
Applying Filters with Jinja
2235
----------------------------
2336

24-
To use a filter ``my_filter`` on ``foo``, you use the pipe operator, e.g.: ``{{foo | my_filter}}``.
37+
To use a filter ``my_filter`` on ``foo``, you use the pipe operator, e.g.: ``{{ foo | my_filter }}``.
2538
Please pay attention to the data type and available filters for each data type. Since Jinja is a
2639
text templating language, all your input is converted to text and then manipulations happen on that
2740
value. The necessary casting at the end is done by |st2| based on information you provide in YAML
@@ -64,11 +77,28 @@ function in Mistral workflows natively supports decryption via the ``decrypt`` p
6477
.. note::
6578

6679
Because of a bug in Mistral, these filters do not currently support the "pipe" operator filter
67-
format (`|`) So, instead of ``'{{ _.input_str | regex_match(_.regex_pattern)}}'`` you would
80+
format (`|`) So, instead of ``'{{ _.input_str | regex_match(_.regex_pattern) }}'`` you would
6881
call the filter like a regular function, moving the previously input value into the first
69-
positional argument position: ``'{{ regex_match(_.input_str, _.regex_pattern)}}'``. This will
82+
positional argument position: ``'{{ regex_match(_.input_str, _.regex_pattern) }}'``. This will
7083
be addressed in a future release.
7184

85+
from_json_string
86+
~~~~~~~~~~~~~~~~
87+
88+
Converts a JSON string into an object or array (opposite of ``to_json_string``).
89+
90+
.. code-block:: bash
91+
92+
{{ value_key | from_json_string }}
93+
94+
from_yaml_string
95+
~~~~~~~~~~~~~~~~
96+
97+
Converts a YAML string into an object or array (opposite of ``to_yaml_string``).
98+
99+
.. code-block:: bash
100+
101+
{{ value_key | from_yaml_string }}
72102
73103
json_escape
74104
~~~~~~~~~~~
@@ -77,7 +107,76 @@ Adds escape characters to JSON strings.
77107

78108
.. code-block:: bash
79109
80-
{{value_key | json_escape}}
110+
{{ value_key | json_escape }}
111+
112+
jsonpath_query
113+
~~~~~~~~~~~~~~
114+
115+
Provides the ability to extract data from complex ``object`` data using the
116+
`JSONPath <http://goessner.net/articles/JsonPath/>` query language. More specifically
117+
we use the ``jsonpath-rw`` library that has its own extensions, details can be
118+
found on the `jsonpath-rw GitHub page <https://github.com/kennknowles/python-jsonpath-rw/tree/master/jsonpath_rw>`.
119+
Data passed into this function should be of type ``object`` or ``array``.
120+
The result of this function will either be an array of results, or None if the
121+
query did not return any results.
122+
If you would like to test out your JSONPath queries prior to utilizing this filter
123+
an online evaluator can be found `here <http://jsonpath.com/>`.
124+
125+
.. code-block:: bash
126+
127+
# Access an element in a data structure. Each level is delimited by a '.'.
128+
# Each part of the query is the name of the field in the current level
129+
# of the data structure.
130+
#
131+
# input = {'a': {'b': {'c': 1234} } }
132+
# result = [1234]
133+
{{ input | jsonpath_query('a.b.c') }}
134+
135+
# Access an index in an array/list
136+
#
137+
# input = {'animals': ['bird', 'rabbit', 'cat', 'dog', 'cow'] }
138+
# result = ['rabbit']
139+
{{ input | jsonpath_query('animals[1]') }}
140+
141+
# Access all indexes in an array/list
142+
#
143+
# input = {'animals': ['bird', 'rabbit', 'cat', 'dog', 'cow'] }
144+
# result = ['bird', 'rabbit', 'cat', 'dog', 'cow']
145+
{{ input | jsonpath_query('animals[*]') }}
146+
147+
# Access a range/slice of indexes in an array/list.
148+
# These expressions can be read mathematically as [first, last)
149+
# Meaning that the index of the first element is inclusive, and the index
150+
# of the last element is exclusive (will not be included).
151+
#
152+
# input = {'animals': ['bird', 'rabbit', 'cat', 'dog', 'sheep'] }
153+
# result = ['rabbit', 'cat']
154+
{{ input | jsonpath_query('animals[1:3]') }}
155+
156+
# If you leave out the first number in the range/slice operator
157+
# it will start at the beginning implicitly. It can be read as:
158+
# "give me all data from the beginning to the index specified"
159+
#
160+
# input = {'animals': ['bird', 'rabbit', 'cat', 'dog', 'sheep'] }
161+
# result = ['bird', 'rabbit']
162+
{{ input | jsonpath_query('animals[:2]') }}
163+
164+
# If you leave out the last number in the range/slice operator
165+
# it will go all the way to the end of the array implicitly.
166+
# It can be read as: "give me all data from the index specified to the end"
167+
#
168+
# input = {'animals': ['bird', 'rabbit', 'cat', 'dog', 'sheep'] }
169+
# result = ['cat', 'dog', 'sheep']
170+
{{ input | jsonpath_query('animals[2:]') }}
171+
172+
# Access a field within every element of an array.
173+
#
174+
# input = {'people': [{'first': 'James', 'last': 'd'},
175+
# {'first': 'Jacob', 'last': 'e'},
176+
# {'first': 'Jayden', 'last': 'f'}]}
177+
# result = ['James', 'Jacob', 'Jayden']
178+
{{ input | jsonpath_query('people[*].first') }}
179+
81180
82181
regex_match
83182
~~~~~~~~~~~
@@ -86,8 +185,8 @@ Search for the pattern at beginning of the string. Returns True if found, False
86185

87186
.. code-block:: bash
88187
89-
{{value_key | regex_match('x')}}
90-
{{value_key | regex_match("^v(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)$")}}
188+
{{ value_key | regex_match('x') }}
189+
{{ value_key | regex_match("^v(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)$") }}
91190
92191
regex_replace
93192
~~~~~~~~~~~~~
@@ -100,8 +199,8 @@ Replaces substring that matches pattern with provided replacement value (backref
100199

101200
.. code-block:: bash
102201
103-
{{value_key | regex_replace("x", "y")}}
104-
{{value_key | regex_replace("(blue|white|red)", "beautiful color \\\\1")}}
202+
{{ value_key | regex_replace("x", "y") }}
203+
{{ value_key | regex_replace("(blue|white|red)", "beautiful color \\\\1") }}
105204
106205
regex_search
107206
~~~~~~~~~~~~
@@ -110,8 +209,8 @@ Search for pattern anywhere in the string. Returns True if found, False if not.
110209

111210
.. code-block:: bash
112211
113-
{{value_key | regex_search("y")}}
114-
{{value_key | regex_search("^v(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)$")}}
212+
{{ value_key | regex_search("y") }}
213+
{{ value_key | regex_search("^v(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)$") }}
115214
116215
regex_substring
117216
~~~~~~~~~~~~~~~
@@ -121,8 +220,8 @@ Searches for the provided pattern in a string, and returns the first matched reg
121220

122221
.. code-block:: bash
123222
124-
{{value_key | regex_substring("y")}}
125-
{{value_key | regex_substring("^v(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)$")}}
223+
{{ value_key | regex_substring("y") }}
224+
{{ value_key | regex_substring("^v(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)$") }}
126225
127226
to_complex
128227
~~~~~~~~~~
@@ -131,7 +230,7 @@ Convert data to JSON string (see ``to_json_string`` for a more flexible option)
131230

132231
.. code-block:: bash
133232
134-
{{value_key | to_complex}}
233+
{{ value_key | to_complex }}
135234
136235
to_human_time_from_seconds
137236
~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -140,7 +239,7 @@ Given time elapsed in seconds, this filter converts it to human readable form li
140239

141240
.. code-block:: bash
142241
143-
{{ value_key | to_human_time_from_seconds}}
242+
{{ value_key | to_human_time_from_seconds }}
144243
145244
to_json_string
146245
~~~~~~~~~~~~~~
@@ -149,7 +248,7 @@ Convert data to JSON string.
149248

150249
.. code-block:: bash
151250
152-
{{value_key | to_json_string}}
251+
{{ value_key | to_json_string }}
153252
154253
to_yaml_string
155254
~~~~~~~~~~~~~~
@@ -158,7 +257,7 @@ Convert data to YAML string.
158257

159258
.. code-block:: bash
160259
161-
{{value_key | to_yaml_string}}
260+
{{ value_key | to_yaml_string }}
162261
163262
use_none
164263
~~~~~~~~
@@ -167,7 +266,7 @@ If value being filtered is None, this filter will return the string ``%*****__%N
167266

168267
.. code-block:: bash
169268
170-
{{value_key | use_none}}
269+
{{ value_key | use_none }}
171270
172271
version_bump_major
173272
~~~~~~~~~~~~~~~~~~
@@ -176,7 +275,7 @@ Bumps up the major version of supplied version field.
176275

177276
.. code-block:: bash
178277
179-
{{version | version_bump_major}}
278+
{{ version | version_bump_major }}
180279
181280
version_bump_minor
182281
~~~~~~~~~~~~~~~~~~
@@ -185,7 +284,7 @@ Bumps up the minor version of supplied version field.
185284

186285
.. code-block:: bash
187286
188-
{{version | version_bump_minor}}
287+
{{ version | version_bump_minor }}
189288
190289
version_bump_patch
191290
~~~~~~~~~~~~~~~~~~
@@ -194,7 +293,7 @@ Bumps up the patch version of supplied version field.
194293

195294
.. code-block:: bash
196295
197-
{{version | version_bump_patch}}
296+
{{ version | version_bump_patch }}
198297
199298
version_compare
200299
~~~~~~~~~~~~~~~
@@ -204,7 +303,7 @@ Compare a semantic version to another value. Returns 1 if LHS is greater or -1 i
204303

205304
.. code-block:: bash
206305
207-
{{version | version_compare("0.10.1")}}
306+
{{ version | version_compare("0.10.1") }}
208307
209308
version_equal
210309
~~~~~~~~~~~~~
@@ -213,19 +312,19 @@ Returns True if LHS version is equal to RHS version.
213312

214313
.. code-block:: bash
215314
216-
{{version | version_equal("0.10.0")}}
315+
{{ version | version_equal("0.10.0") }}
217316
218317
version_less_than
219318
~~~~~~~~~~~~~~~~~
220319

221320
Returns True if LHS version is lesser than RHS version. Both inputs have to follow semantic version
222321
syntax.
223322

224-
E.g. ``{{“1.6.0” | version_less_than("1.7.0")}}``.
323+
E.g. ``{{ “1.6.0” | version_less_than("1.7.0") }}``.
225324

226325
.. code-block:: bash
227326
228-
{{version | version_less_than("0.9.2")}}
327+
{{ version | version_less_than("0.9.2") }}
229328
230329
version_match
231330
~~~~~~~~~~~~~
@@ -237,19 +336,19 @@ Supports operators ``>``, ``<``, ``==``, ``<=``, and ``>=``.
237336

238337
.. code-block:: bash
239338
240-
{{version | version_match(">0.10.0")}}
339+
{{ version | version_match(">0.10.0") }}
241340
242341
version_more_than
243342
~~~~~~~~~~~~~~~~~
244343

245344
Returns True if LHS version is greater than RHS version. Both inputs have to follow semantic
246345
version syntax.
247346

248-
E.g. ``{{"1.6.0” | version_more_than("1.7.0")}}``.
347+
E.g. ``{{ "1.6.0” | version_more_than("1.7.0") }}``.
249348

250349
.. code-block:: bash
251350
252-
{{version | version_more_than("0.10.1")}}
351+
{{ version | version_more_than("0.10.1") }}
253352
254353
version_strip_patch
255354
~~~~~~~~~~~~~~~~~~~
@@ -258,4 +357,4 @@ Drops patch version of supplied version field.
258357

259358
.. code-block:: bash
260359
261-
{{version | version_strip_patch}}
360+
{{ version | version_strip_patch }}

0 commit comments

Comments
 (0)