Skip to content

Commit f18c808

Browse files
authored
🐛 Fix json_extract Construction (#772)
Restructures the way the dsl builds the SQL expression to access JSON properties so that properties with a . in are correctly treated as a single key Adds a test to check for correct behaviour when accessing a property containing a . Addresses issue #771 Would like to check with John if removing `json.dumps()` is ok. I couldn't see a reason it was necessary and all tests pass/all the use-cases I tried worked fine, but maybe there is one I missed.
1 parent 41b9f37 commit f18c808

File tree

2 files changed

+22
-5
lines changed

2 files changed

+22
-5
lines changed

tests/test_dsl.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"neg": -1,
4747
"bool": True,
4848
"nesting": {"fib": [1, 1, 2, 3, 5], "foo": {"bar": "baz"}},
49+
"dot.key": 3.14,
4950
}
5051

5152

@@ -105,8 +106,8 @@ def test_prop_or_prop() -> None:
105106
{},
106107
)
107108
assert str(query) == (
108-
'((json_extract(properties, "$.int") == 2) OR '
109-
'(json_extract(properties, "$.int") == 3))'
109+
"""((json_extract(properties, '$."int"') == 2) OR """
110+
"""(json_extract(properties, '$."int"') == 3))"""
110111
)
111112

112113

@@ -571,3 +572,19 @@ def test_contains_str(
571572
eval_locals,
572573
)
573574
assert bool(check(result)) is True
575+
576+
@staticmethod
577+
def test_key_with_period(
578+
eval_globals: dict[str, object],
579+
eval_locals: Mapping[str, object],
580+
check: Callable,
581+
) -> None:
582+
"""Test key with period."""
583+
query = "props['dot.key']"
584+
result = eval( # skipcq: PYL-W0123 # noqa: S307
585+
query,
586+
eval_globals,
587+
eval_locals,
588+
)
589+
590+
assert check(result) == 3.14

tiatoolbox/annotation/dsl.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -265,14 +265,14 @@ def __init__(self: SQLJSONDictionary, acc: str | None = None) -> None:
265265

266266
def __str__(self: SQLJSONDictionary) -> str:
267267
"""Return a human-readable, or informal, string representation of an object."""
268-
return f"json_extract(properties, {json.dumps(f'$.{self.acc}')})"
268+
return f"json_extract(properties, '$.{self.acc}')"
269269

270270
def __getitem__(self: SQLJSONDictionary, key: str) -> SQLJSONDictionary:
271271
"""Get an item from the dataset."""
272-
key_str = f"[{key}]" if isinstance(key, (int,)) else str(key)
272+
key_str = f"[{key}]" if isinstance(key, (int,)) else f'"{key}"'
273273

274274
joiner = "." if self.acc and not isinstance(key, int) else ""
275-
return SQLJSONDictionary(acc=self.acc + joiner + f"{key_str}")
275+
return SQLJSONDictionary(acc=self.acc + joiner + key_str)
276276

277277
def get(
278278
self: SQLJSONDictionary,

0 commit comments

Comments
 (0)