Skip to content

Commit

Permalink
Support Cursor
Browse files Browse the repository at this point in the history
  • Loading branch information
AliRn76 committed Mar 19, 2024
1 parent 788546d commit 3a437c2
Show file tree
Hide file tree
Showing 4 changed files with 215 additions and 72 deletions.
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,9 @@ PantherDB is a <b>Simple</b>, <b>FileBase</b> and <b>Document Oriented</b> datab
```python
users: list[PantherDocument] = db.collection('User').find(last_name='Rn')
```

- #### All documents:
or all documents
```python
users: list[PantherDocument] = db.collection('User').all()
users: list[PantherDocument] = db.collection('User').find()
```

- #### Count documents:
Expand Down
7 changes: 2 additions & 5 deletions pantherdb/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
from pantherdb.pantherdb import * # noqa: F403
from pantherdb.pantherdb import PantherDB, PantherCollection, PantherDocument, PantherDBException, Cursor

__version__ = '1.4.0'


__all__ = ('__version__', 'PantherDB', 'PantherCollection', 'PantherDocument', 'PantherDBException')
__version__ = '2.0.0'
79 changes: 58 additions & 21 deletions pantherdb/pantherdb.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
from __future__ import annotations

import typing
from pathlib import Path
from typing import ClassVar, Iterator
from typing import ClassVar, Iterator, Any, List, Tuple, Union

import orjson as json

Expand All @@ -17,8 +16,9 @@ class PantherDB:
_instances: ClassVar[dict] = {}
db_name: str = 'database.pdb'
__secret_key: bytes | None
__fernet: typing.Any # type[cryptography.fernet.Fernet | None]
__fernet: Any # type[cryptography.fernet.Fernet | None]
__return_dict: bool
__return_cursor: bool
__content: dict
__ulid: ULID

Expand All @@ -36,6 +36,8 @@ def __new__(cls, *args, **kwargs):
# Replace with .removesuffix('.pdb') after python3.8 compatible support
if db_name.endswith('.pdb'):
db_name = db_name[:-4]
elif db_name.endswith('.json'):
db_name = db_name[:-5]

if db_name not in cls._instances:
cls._instances[db_name] = super().__new__(cls)
Expand All @@ -46,9 +48,11 @@ def __init__(
db_name: str | None = None,
*,
return_dict: bool = False,
return_cursor: bool = False,
secret_key: bytes | None = None,
):
self.__return_dict = return_dict
self.__return_cursor = return_cursor
self.__secret_key = secret_key
self.__ulid = ULID()
self.__content = {}
Expand All @@ -60,8 +64,11 @@ def __init__(
self.__fernet = None

if db_name:
if not db_name.endswith('pdb'):
db_name = f'{db_name}.pdb'
if not db_name.endswith(('pdb', 'json')):
if self.__secret_key:
db_name = f'{db_name}.pdb'
else:
db_name = f'{db_name}.json'
self.db_name = db_name
Path(self.db_name).touch(exist_ok=True)

Expand All @@ -76,6 +83,10 @@ def __str__(self) -> str:
def content(self) -> dict:
return self.__content

@property
def return_cursor(self) -> bool:
return self.__return_cursor

@property
def return_dict(self) -> bool:
return self.__return_dict
Expand Down Expand Up @@ -110,16 +121,18 @@ def _refresh(self) -> None:
else:
try:
decrypted_data: bytes = self.__fernet.decrypt(data)
self.__content = json.loads(decrypted_data)
except Exception: # type[cryptography.fernet.InvalidToken]
error = '"secret_key" Is Not Valid'
raise PantherDBException(error)

self.__content = json.loads(decrypted_data)

def collection(self, collection_name: str) -> PantherCollection:
return PantherCollection(
db_name=self.db_name,
collection_name=collection_name,
return_dict=self.return_dict,
return_cursor=self.return_cursor,
secret_key=self.secret_key,
)

Expand All @@ -136,9 +149,10 @@ def __init__(
*,
collection_name: str,
return_dict: bool,
return_cursor: bool,
secret_key: bytes,
):
super().__init__(db_name=db_name, return_dict=return_dict, secret_key=secret_key)
super().__init__(db_name=db_name, return_dict=return_dict, return_cursor=return_cursor, secret_key=secret_key)
self.__collection_name = collection_name

def __str__(self) -> str:
Expand Down Expand Up @@ -167,6 +181,7 @@ def __create_result(self, data: dict, /) -> PantherDocument | dict:
db_name=self.db_name,
collection_name=self.collection_name,
return_dict=self.return_dict,
return_cursor=self.return_cursor,
secret_key=self.secret_key,
**data,
)
Expand Down Expand Up @@ -213,17 +228,14 @@ def find_one(self, **kwargs) -> PantherDocument | dict | None:
# Return the first document
return d

def find(self, **kwargs) -> list[PantherDocument | dict]:
def find(self, **kwargs) -> Cursor | List[PantherDocument | dict]:
documents = self._get_collection()

# Empty Collection
if not documents:
return []
result = [d for _, d in self._find(documents, **kwargs) if d is not None]

if not kwargs:
return self.all()

return [d for _, d in self._find(documents, **kwargs) if d is not None]
if self.return_cursor:
return Cursor(result)
return result

def first(self, **kwargs) -> PantherDocument | dict | None:
return self.find_one(**kwargs)
Expand All @@ -243,12 +255,6 @@ def last(self, **kwargs) -> PantherDocument | dict | None:
# Return the first one
return d

def all(self) -> list[PantherDocument | dict]:
if self.return_dict:
return self._get_collection()
else:
return [self.__create_result(r) for r in self._get_collection()]

def insert_one(self, **kwargs) -> PantherDocument | dict:
documents = self._get_collection()
kwargs['_id'] = self.ulid.new()
Expand Down Expand Up @@ -372,6 +378,7 @@ def __init__(
*,
collection_name: str,
return_dict: bool,
return_cursor: bool,
secret_key: bytes,
**kwargs,
):
Expand All @@ -380,6 +387,7 @@ def __init__(
db_name=db_name,
collection_name=collection_name,
return_dict=return_dict,
return_cursor=return_cursor,
secret_key=secret_key,
)

Expand All @@ -399,6 +407,7 @@ def __getattr__(self, item: str):
def __setattr__(self, key, value):
if key not in [
'_PantherDB__return_dict',
'_PantherDB__return_cursor',
'_PantherDB__secret_key',
'_PantherDB__content',
'_PantherDB__fernet',
Expand All @@ -414,6 +423,10 @@ def __setattr__(self, key, value):

super().__setattr__(key, value)

__setitem__ = __setattr__

__getitem__ = __getattr__

@property
def id(self) -> int:
return self.data['_id']
Expand All @@ -434,3 +447,27 @@ def save(self) -> None:

def json(self) -> str:
return json.dumps(self.data).decode()


class Cursor:
def __init__(self, documents: List[dict | PantherDocument]):
self.documents = documents
self._cursor = 0

def next(self):
try:
result = self.documents[self._cursor]
except IndexError:
raise StopIteration
self._cursor += 1
return result

__next__ = next

def __getitem__(self, index: int | slice) -> Union[Cursor, dict, ...]:
return self.documents[index]

def sort(self, sorts: List[Tuple[str, int]]):
for sort in sorts[::-1]:
self.documents.sort(key=lambda x: x[sort[0]], reverse=bool(sort[1] == -1))
return self
Loading

0 comments on commit 3a437c2

Please sign in to comment.