Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 52 additions & 3 deletions DictDots.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import re
import constants
from typing import Any
from dd_types import DotSearchable, DotQuery, DotCurrentKey, DotCurrentData
from dd_types import DotSearchable, DotQuery, DotCurrentKey, DotCurrentData, DotFilterResult
from dd_exceptions import InvalidQueryString, InvalidDataType, DoesNotExist, KeyNotFound


class DictDots:
@staticmethod
def is_valid_query(query: DotQuery) -> bool:
def is_valid_get_query(query: DotQuery) -> bool:
"""Check if the query string has only valid characters.

Queries, for the time being, only allow alphanumeric and dots ``.``
Expand All @@ -19,6 +19,10 @@ def is_valid_query(query: DotQuery) -> bool:
"""
return bool(re.match(r'^[\w.]+$', query))

@classmethod
def is_valid_filter_query(query: DotQuery):
return bool(re.match(r'^[\w.\[\]{}]+$', query))

@staticmethod
def is_searchable_type(data: Any) -> bool:
"""Check that the data can be searched by DictDots.
Expand All @@ -44,7 +48,7 @@ def _validate_get(searchable: DotSearchable, query: DotQuery) -> None:
if not DictDots.is_searchable_type(searchable):
raise InvalidDataType(searchable)

if not DictDots.is_valid_query(query):
if not DictDots.is_valid_get_query(query):
raise InvalidQueryString(query)

@staticmethod
Expand Down Expand Up @@ -104,5 +108,50 @@ def get(cls, searchable: DotSearchable, query: DotQuery, default: Any = None) ->

return current_data

@classmethod
def filter(cls, searchable: DotSearchable, query: DotQuery) -> DotFilterResult:
"""Query a searchable

Attempt to find values in a searchable matching the key from the search string.
Returns a list of all matches.
Will return an empty list if no matches are found.

Does not raise an error for invalid keys because this is a search.

:param DotSearchable searchable:
The data to query.
:param DotQuery query:
A query string to search the data for.
:return DotFilterResult:
A list of all data matching the search string in ``query``.
May be empty.
"""
DictDots._validate_get(searchable, query)
keys = query.split('.')
# current_data is the value we are currently digging into.
current_data = searchable

type_methods = {
dict: cls._dict_getter,
list: cls._list_getter,
}

for key in keys:
if key.isnumeric():
# We don't support numerical strings for now, so convert them to ints.
key = int(key)

method = type_methods[type(current_data)]

try:
current_data = method(key, current_data)
except KeyNotFound as e:
if default:
return default
raise DoesNotExist(query, searchable, e)

return current_data




3 changes: 3 additions & 0 deletions dd_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@

"""A type representing the accepted data types for getter functions."""
DotCurrentData = DotSearchable

"""The result of a filter query. Can be empty."""
DotFilterResult = List[Any]
2 changes: 2 additions & 0 deletions docs/ddql.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# Potential data language

---
This is a wishlist of how I want the query language to look.
The only things on here that work right now are `get s` and `get ns`.

I haven't yet decided if I actually want to support sets due to how
the indexing works through a hash. It would be cumbersome to try and
pass a big value into dictdots in the query string.

## Get

Get returns a specific object matching an exact query.
Expand Down
2 changes: 1 addition & 1 deletion tests/test_dict_dots.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
])
def test_is_valid_query(query, result):
"""Test that queries can be validated."""
assert DictDots.is_valid_query(query) == result
assert DictDots.is_valid_get_query(query) == result


@pytest.mark.parametrize("data,expected", [
Expand Down