Skip to content

Commit b5da1d4

Browse files
authored
Merge pull request #64 from jg-rp/compiled-select
Allow `Query.select()` to accept precompiled paths
2 parents c1710ae + 586fbc2 commit b5da1d4

File tree

3 files changed

+22
-7
lines changed

3 files changed

+22
-7
lines changed

docs/query.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,12 +166,16 @@ for product in query("$..products.*", data).values():
166166
{'title': 'Beanie', 'description': 'Winter running hat.', 'price': 9.0}
167167
```
168168

169-
We can select nested values too.
169+
We can select nested values too, and arguments to `select()` can be pre-compiled paths.
170170

171171
```python
172+
import jsonpath
173+
172174
# ...
173175

174-
for product in query("$..products.*", data).select("title", "social.shares"):
176+
projection = (jsonpath.compile("title"), jsonpath.compile("social.shares"))
177+
178+
for product in jsonpath.query("$..products.*", data).select(*projection):
175179
print(product)
176180
```
177181

jsonpath/fluent_api.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
from .patch import JSONPatch
2323

2424
if TYPE_CHECKING:
25+
from jsonpath import CompoundJSONPath
26+
from jsonpath import JSONPath
2527
from jsonpath import JSONPathEnvironment
2628
from jsonpath import JSONPathMatch
2729
from jsonpath import JSONPointer
@@ -191,7 +193,7 @@ def take(self, n: int) -> Query:
191193

192194
def select(
193195
self,
194-
*expressions: str,
196+
*expressions: Union[str, JSONPath, CompoundJSONPath],
195197
projection: Projection = Projection.RELATIVE,
196198
) -> Iterable[object]:
197199
"""Query projection using relative JSONPaths.
@@ -217,7 +219,7 @@ def select(
217219
def _select(
218220
self,
219221
match: JSONPathMatch,
220-
expressions: Tuple[str, ...],
222+
expressions: Tuple[Union[str, JSONPath, CompoundJSONPath], ...],
221223
projection: Projection,
222224
) -> object:
223225
if isinstance(match.obj, str):
@@ -232,20 +234,21 @@ def _select(
232234
patch = JSONPatch()
233235

234236
for expr in expressions:
235-
self._patch(match, expr, patch, projection)
237+
path = self._env.compile(expr) if isinstance(expr, str) else expr
238+
self._patch(match, path, patch, projection)
236239

237240
return _fix_sparse_arrays(patch.apply(obj))
238241

239242
def _patch(
240243
self,
241244
match: JSONPathMatch,
242-
expr: str,
245+
path: Union[JSONPath, CompoundJSONPath],
243246
patch: JSONPatch,
244247
projection: Projection,
245248
) -> None:
246249
root_pointer = match.pointer()
247250

248-
for rel_match in self._env.finditer(expr, match.obj): # type: ignore
251+
for rel_match in path.finditer(match.obj): # type: ignore
249252
if projection == Projection.FLAT:
250253
patch.addap("/-", rel_match.obj)
251254
elif projection == Projection.ROOT:

tests/test_query_projection.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,3 +159,11 @@ def test_sparse_array_selection() -> None:
159159
assert list(it) == [
160160
{"categories": [{"products": [{"title": "Beanie", "social": {"shares": 7}}]}]}
161161
]
162+
163+
164+
def test_pre_compiled_select_many() -> None:
165+
expr = "$.*"
166+
data = [{"a": 1, "b": 1, "c": 1}, {"a": 2, "b": 2, "c": 2}, {"b": 3, "a": 3}]
167+
projection = (jsonpath.compile("a"), "c")
168+
it = jsonpath.query(expr, data).select(*projection)
169+
assert list(it) == [{"a": 1, "c": 1}, {"a": 2, "c": 2}, {"a": 3}]

0 commit comments

Comments
 (0)