Skip to content
Merged
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
2 changes: 1 addition & 1 deletion nitro_datastore/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@
from nitro_datastore.datastore import NitroDataStore
from nitro_datastore.query_builder import QueryBuilder

__version__ = "1.0.4"
__version__ = "1.0.5"
__all__ = ["NitroDataStore", "QueryBuilder"]
48 changes: 44 additions & 4 deletions nitro_datastore/datastore.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,13 @@ def has(self, key: str) -> bool:

Raises:
ValueError: If key is empty, whitespace-only, or has empty segments

Example:
>>> data = NitroDataStore({'site': {'name': 'My Site'}})
>>> data.has('site.name')
True
>>> data.has('site.missing')
False
"""
self._validate_path(key)

Expand All @@ -382,8 +389,20 @@ def has(self, key: str) -> bool:
def merge(self, other: Union["NitroDataStore", Dict[str, Any]]) -> None:
"""Deep merge another data store or dictionary into this one.

Mutates this datastore in place. Nested dicts are merged recursively;
non-dict values (including lists) from `other` overwrite existing values.

Args:
other: Another NitroDataStore or dict to merge in
other: Another NitroDataStore or dict to merge in.

Raises:
ValueError: If a circular reference is detected during merge.

Example:
>>> data = NitroDataStore({'site': {'name': 'A', 'theme': 'dark'}})
>>> data.merge({'site': {'theme': 'light', 'url': 'a.com'}})
>>> data.to_dict()
{'site': {'name': 'A', 'theme': 'light', 'url': 'a.com'}}
"""
if isinstance(other, NitroDataStore):
other_data = other._data
Expand All @@ -396,17 +415,38 @@ def merge(self, other: Union["NitroDataStore", Dict[str, Any]]) -> None:
def to_dict(self) -> Dict[str, Any]:
"""Export data as a plain dictionary.

Returns a deep copy, so mutations on the result do not affect the
datastore (and vice versa).

Returns:
A deep copy of the internal data dictionary
A deep copy of the internal data dictionary.

Raises:
ValueError: If a circular reference is detected during the copy.

Example:
>>> data = NitroDataStore({'site': {'name': 'My Site'}})
>>> plain = data.to_dict()
>>> plain['site']['name'] = 'Mutated'
>>> data.get('site.name')
'My Site'
"""
return self._deep_copy(self._data)

def save(self, file_path: Union[str, Path], indent: int = 2) -> None:
"""Save data to a JSON file.

Creates parent directories if they do not exist. Non-ASCII characters
are written as-is (UTF-8 encoded, not escaped).

Args:
file_path: Path to save JSON file
indent: JSON indentation (default: 2)
file_path: Destination JSON file path.
indent: JSON indentation in spaces. Defaults to 2.

Example:
>>> data = NitroDataStore({'site': {'name': 'My Site'}})
>>> data.save('output/config.json')
>>> data.save('output/compact.json', indent=0)
"""
path = Path(file_path)
path.parent.mkdir(parents=True, exist_ok=True)
Expand Down
12 changes: 8 additions & 4 deletions nitro_datastore/query_builder.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Query builder for filtering and transforming collections."""

from typing import Any, Callable, List, Optional
from typing import Any, Callable, Dict, List, Optional


class QueryBuilder:
Expand Down Expand Up @@ -169,14 +169,18 @@ def pluck(self, key: str) -> List[Any]:
results = self.execute()
return [item.get(key) if isinstance(item, dict) else None for item in results]

def group_by(self, key: str) -> dict:
def group_by(self, key: str) -> Dict[Any, List[Any]]:
"""Group results by a field value.

Non-dict items in the result set are skipped. Items missing `key` are
grouped under `None`.

Args:
key: Key to group by
key: Field name to group by.

Returns:
Dictionary mapping key values to lists of items
Mapping from each distinct field value to the list of items
that share it.

Example:
>>> by_category = query.group_by('category')
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "nitro-datastore"
version = "1.0.4"
version = "1.0.5"
description = "Schema-agnostic JSON data store with dot notation, chainable queries, bulk operations, and built-in security features"
readme = "README.md"
authors = [
Expand Down
Loading