diff --git a/.gitignore b/.gitignore index 681ba31..9f7550b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ __pycache__ -src/Rocketstore/test +.venv diff --git a/CITATION.cff b/CITATION.cff index fc648f6..fb0cd0b 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -17,4 +17,4 @@ keywords: - file - rocket license: MIT -version: 0.0.6 +version: 0.0.7 diff --git a/MANIFEST.in b/MANIFEST.in index 2d6b4b3..fdef19d 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -4,4 +4,6 @@ include README.md include *.toml recursive-include src *.py recursive-include src/Rocketstore *.py -recursive-include src/Rocketstore/utils *.py \ No newline at end of file +recursive-include src/Rocketstore/utils *.py +prune */__pycache__ +recursive-exclude Samples/* \ No newline at end of file diff --git a/README.md b/README.md index b51a8dd..1cba35a 100644 --- a/README.md +++ b/README.md @@ -48,18 +48,31 @@ Compare Rocket-Store, SQL and file system terms: To use Rocketstore, you must first import the library: ```python -from Rocketstore import Rocketstore, _FORMAT_JSON +from Rocketstore import Rocketstore rs = Rocketstore() +``` + +usage of constants: +```python + +#method 1: +rs = Rocketstore() +rs.post(..., rs._FORMAT_JSON) + +#or + +rs.post(..., Rocketstore._FORMAT_JSON) ``` + ### Post ```python -rs.post(collection="delete_fodders1", key="1", record={"some":"json input"}, flags=_FORMAT_JSON) +rs.post(collection="delete_fodders1", key="1", record={"some":"json input"}, flags=Rocketstore._FORMAT_JSON) # or -rs.post("delete_fodders1", "1", {"some":"json input"}, _FORMAT_JSON) +rs.post("delete_fodders1", "1", {"some":"json input"}, Rocketstore._FORMAT_JSON) ``` Stores a record in a collection identified by a unique key @@ -153,10 +166,10 @@ __Options__: * data_format: Specify which format the records are stored in. Values are: _FORMAT_NATIVE - default. and RS_FORMAT_JSON - Use JSON data format. ```python -rs.options(data_format=_FORMAT_JSON) +rs.options(data_format=Rocketstore._FORMAT_JSON) # or rs.options(**{ - "data_format": _FORMAT_JSON, + "data_format": Rocketstore._FORMAT_JSON, ... }) ``` diff --git a/Samples/Post/README.md b/Samples/Post/README.md deleted file mode 100644 index 0088be9..0000000 --- a/Samples/Post/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Sample implementation - -1) create virtual environment `virtual ./.venv` -2) activate it ` . ./venv/bin/activate` -3) install dependencies `pip install Rocket-Store` -4) run test `python test.py` \ No newline at end of file diff --git a/Samples/Post/test.py b/Samples/Post/test.py deleted file mode 100644 index 4a1b153..0000000 --- a/Samples/Post/test.py +++ /dev/null @@ -1,22 +0,0 @@ -from Rocketstore import Rocketstore, _ADD_AUTO_INC - -rs = Rocketstore(**{"data_storage_area": "./test"}) - -print(rs) - -dataInput = { - "content": "hello asfalsdfsalfaslflasl", - "embeddings": [0.2, 0.31231312, 0.111], -} - - -out = rs.post("glOtc6EzYQTZEt0J18cU1f4Ycdz1H8WWTDVkBQTp1Gv2BWgb", - "memories", dataInput) - -print(out) - - -out = rs.post("glOtc6EzYQTZEt0J18cU1f4Ycdz1H8WWTDVkBQTp1Gv2BWgb", - "memories", dataInput, _ADD_AUTO_INC) - -print(out) diff --git a/dist/Rocket-Store-0.0.5.tar.gz b/dist/Rocket-Store-0.0.5.tar.gz deleted file mode 100644 index 185ccfc..0000000 Binary files a/dist/Rocket-Store-0.0.5.tar.gz and /dev/null differ diff --git a/dist/Rocket_Store-0.0.5-py3-none-any.whl b/dist/Rocket_Store-0.0.5-py3-none-any.whl deleted file mode 100644 index 68f258f..0000000 Binary files a/dist/Rocket_Store-0.0.5-py3-none-any.whl and /dev/null differ diff --git a/pyproject.toml b/pyproject.toml index 1447d1b..0c91624 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "Rocket-Store" -version = "0.0.6" +version = "0.0.7" authors = [ { name="Anton Sychev", email="anton@sychev.xyz" }, ] diff --git a/src/Rocket_Store.egg-info/PKG-INFO b/src/Rocket_Store.egg-info/PKG-INFO index 5ce4e6e..7e2d8c2 100644 --- a/src/Rocket_Store.egg-info/PKG-INFO +++ b/src/Rocket_Store.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: Rocket-Store -Version: 0.0.5 +Version: 0.0.7 Summary: Using the filesystem as a searchable database. Author-email: Anton Sychev License: Rocket Store @@ -90,18 +90,31 @@ Compare Rocket-Store, SQL and file system terms: To use Rocketstore, you must first import the library: ```python -from Rocketstore import Rocketstore, _FORMAT_JSON +from Rocketstore import Rocketstore rs = Rocketstore() +``` + +usage of constants: +```python + +#method 1: +rs = Rocketstore() +rs.post(..., rs._FORMAT_JSON) + +#or + +rs.post(..., Rocketstore._FORMAT_JSON) ``` + ### Post ```python -rs.post(collection="delete_fodders1", key="1", record={"some":"json input"}, flags=_FORMAT_JSON) +rs.post(collection="delete_fodders1", key="1", record={"some":"json input"}, flags=Rocketstore._FORMAT_JSON) # or -rs.post("delete_fodders1", "1", {"some":"json input"}, _FORMAT_JSON) +rs.post("delete_fodders1", "1", {"some":"json input"}, Rocketstore._FORMAT_JSON) ``` Stores a record in a collection identified by a unique key @@ -195,10 +208,10 @@ __Options__: * data_format: Specify which format the records are stored in. Values are: _FORMAT_NATIVE - default. and RS_FORMAT_JSON - Use JSON data format. ```python -rs.options(data_format=_FORMAT_JSON) +rs.options(data_format=Rocketstore._FORMAT_JSON) # or rs.options(**{ - "data_format": _FORMAT_JSON, + "data_format": Rocketstore._FORMAT_JSON, ... }) ``` @@ -224,9 +237,13 @@ Contributions are welcome. Please open an issue to discuss what you would like t ### Publish to Pypi +***Local:*** ```shell python -m pip install build twine python3 -m build twine check dist/* twine upload dist/* ``` + +***Live:*** +No need do nothing GitHub have Workflow action its publish auto diff --git a/src/Rocket_Store.egg-info/SOURCES.txt b/src/Rocket_Store.egg-info/SOURCES.txt index 5af5c3c..8fc4e09 100644 --- a/src/Rocket_Store.egg-info/SOURCES.txt +++ b/src/Rocket_Store.egg-info/SOURCES.txt @@ -3,13 +3,6 @@ LICENSE MANIFEST.in README.md pyproject.toml -src/RocketStore/RocketStore.py -src/RocketStore/Rocketstore.py -src/RocketStore/__init__.py -src/RocketStore/__version__.py -src/RocketStore/example.py -src/RocketStore/utils/__init__.py -src/RocketStore/utils/files.py src/Rocket_Store.egg-info/PKG-INFO src/Rocket_Store.egg-info/SOURCES.txt src/Rocket_Store.egg-info/dependency_links.txt @@ -18,7 +11,6 @@ src/Rocket_Store.egg-info/top_level.txt src/Rocketstore/Rocketstore.py src/Rocketstore/__init__.py src/Rocketstore/__version__.py -src/Rocketstore/example.py src/Rocketstore/utils/__init__.py src/Rocketstore/utils/files.py tests/test.py \ No newline at end of file diff --git a/src/Rocketstore/Rocketstore.py b/src/Rocketstore/Rocketstore.py index 717a34e..68e1231 100644 --- a/src/Rocketstore/Rocketstore.py +++ b/src/Rocketstore/Rocketstore.py @@ -34,21 +34,6 @@ from .utils.files import file_lock, file_unlock, identifier_name_test, file_name_wash -# Constants -_ORDER = 0x01 # Sort ASC -_ORDER_DESC = 0x02 # Sort DESC -_ORDERBY_TIME = 0x04 # Sort by time not implemented -_LOCK = 0x08 # Lock file -_DELETE = 0x10 # Delete file / collection / database -_KEYS = 0x20 # Return keys only -_COUNT = 0x40 # Return count only -_ADD_AUTO_INC = 0x01 # Add auto incrementing sequence to key -_ADD_GUID = 0x02 # Add Globally Unique IDentifier to key (RFC 4122) -_FORMAT_JSON = 0x01 # Store data in JSON format -_FORMAT_NATIVE = 0x02 # Store data in native format (JSON) -_FORMAT_XML = 0x04 # Store data in XML format -_FORMAT_PHP = 0x08 # Store data in PHP format - # TODO: new binary json format # _FORMAT_BSON = 0x09 #https://en.wikipedia.org/wiki/BSON # _FORMAT_PROTOBUF = 0x10 #https://protobuf.dev/ @@ -59,12 +44,27 @@ class Rocketstore: + # Constants + _ORDER = 0x01 # Sort ASC + _ORDER_DESC = 0x02 # Sort DESC + _ORDERBY_TIME = 0x04 # Sort by time not implemented + _LOCK = 0x08 # Lock file + _DELETE = 0x10 # Delete file / collection / database + _KEYS = 0x20 # Return keys only + _COUNT = 0x40 # Return count only + _ADD_AUTO_INC = 0x01 # Add auto incrementing sequence to key + _ADD_GUID = 0x02 # Add Globally Unique IDentifier to key (RFC 4122) + _FORMAT_JSON = 0x01 # Store data in JSON format + _FORMAT_NATIVE = 0x02 # Store data in native format (JSON) + _FORMAT_XML = 0x04 # Store data in XML format + _FORMAT_PHP = 0x08 # Store data in PHP format + data_storage_area: str = os.path.join(os.path.sep, "tmp", "rsdb") def __init__(self, **set_option) -> None: # https://docs.python.org/es/dev/library/tempfile.html # TODO: use tempdir - self.data_format = _FORMAT_JSON + self.data_format = self._FORMAT_JSON self.lock_retry_interval = 13 self.lock_files = True self.key_cache = {} @@ -76,16 +76,17 @@ def options(self, **options) -> None: ''' inital setup of Rocketstore @Sample: - from Rocketstore import Rocketstore, _FORMAT_JSON, _FORMAT_NATIVE + from Rocketstore import Rocketstore rs.options(**{ "data_storage_area": "./", - "data_format": _FORMAT_NATIVE + "data_format": Rocketstore._FORMAT_NATIVE }) ''' if "data_format" in options: - if options["data_format"] in [_FORMAT_JSON, _FORMAT_XML, _FORMAT_NATIVE]: - self.data_format = options.get("data_format", _FORMAT_JSON) + if options["data_format"] in [self._FORMAT_JSON, self._FORMAT_XML, self._FORMAT_NATIVE]: + self.data_format = options.get( + "data_format", self._FORMAT_JSON) else: raise ValueError( f"Unknown data format: '{options['data_format']}'") @@ -143,12 +144,12 @@ def post(self, collection=None, key=None, record=None, flags=0) -> any: key = "" # Insert a sequence - if len(key) < 1 or flags & _ADD_AUTO_INC: + if len(key) < 1 or flags & self._ADD_AUTO_INC: _sequence = self.sequence(collection) key = f"{_sequence}-{key}" if key else str(_sequence) # Insert a Globally Unique IDentifier - if flags & _ADD_GUID: + if flags & self._ADD_GUID: uid = hex(int(os.urandom(8).hex(), 16))[2:] guid = f"{uid[:8]}-{uid[8:12]}-4000-8{uid[12:15]}-{uid[15:]}" key = f"{guid}-{key}" if len(key) > 0 else guid @@ -158,7 +159,7 @@ def post(self, collection=None, key=None, record=None, flags=0) -> any: os.path.join(self.data_storage_area, collection)) file_name = os.path.join(dir_to_write, key) - if self.data_format & _FORMAT_JSON: + if self.data_format & self._FORMAT_JSON: os.makedirs(dir_to_write, mode=0o775, exist_ok=True) with open(file_name, "w") as file: @@ -209,7 +210,7 @@ def get(self, collection=None, key=None, flags=0, min_time=None, max_time=None) wildcard = not "*" in key or not "?" in key or key == "" or not key - if wildcard and not (flags & _DELETE and (not key or key == "")): + if wildcard and not (flags & self._DELETE and (not key or key == "")): _list = [] # Read directory into cache @@ -238,9 +239,9 @@ def get(self, collection=None, key=None, flags=0, min_time=None, max_time=None) keys = _list # Order by key value - if flags & (_ORDER | _ORDER_DESC) and keys and len(keys) > 1 and not (flags & (_DELETE | (flags & _COUNT))): + if flags & (self._ORDER | self._ORDER_DESC) and keys and len(keys) > 1 and not (flags & (self._DELETE | (flags & self._COUNT))): keys.sort() - if flags & _ORDER_DESC: + if flags & self._ORDER_DESC: keys.reverse() else: if collection and isinstance(self.key_cache.get(collection), list) and key not in self.key_cache[collection]: @@ -250,14 +251,14 @@ def get(self, collection=None, key=None, flags=0, min_time=None, max_time=None) count = len(keys) - if len(keys) > 0 and collection and not (flags & (_KEYS | _COUNT | _DELETE)): + if len(keys) > 0 and collection and not (flags & (self._KEYS | self._COUNT | self._DELETE)): records = [None] * len(keys) for i in range(len(keys)): file_name = os.path.join(scan_dir, keys[i]) # Read JSON record file - if self.data_format & _FORMAT_JSON: + if self.data_format & self._FORMAT_JSON: try: with open(file_name, 'r') as file: records[i] = json.load(file) @@ -271,7 +272,7 @@ def get(self, collection=None, key=None, flags=0, min_time=None, max_time=None) raise ValueError( "Sorry, that data format is not supported") - elif flags & _DELETE: + elif flags & self._DELETE: # DELETE RECORDS print(f"276 DELETE: c({collection}) k({key})") @@ -351,7 +352,7 @@ def get(self, collection=None, key=None, flags=0, min_time=None, max_time=None) records = [e for e in records if e != "*deleted*"] result = {'count': count} - if result['count'] and keys and not (flags & (_COUNT | _DELETE)): + if result['count'] and keys and not (flags & (self._COUNT | self._DELETE)): result['key'] = keys if records: result['result'] = records @@ -362,7 +363,7 @@ def delete(self, collection=None, key=None): ''' Delete one or more records or collections ''' - return self.get(collection=collection, key=key, flags=_DELETE) + return self.get(collection=collection, key=key, flags=self._DELETE) def sequence(self, seq_name: str) -> int: ''' diff --git a/src/Rocketstore/__init__.py b/src/Rocketstore/__init__.py index 684ddd4..d2aff80 100644 --- a/src/Rocketstore/__init__.py +++ b/src/Rocketstore/__init__.py @@ -22,4 +22,4 @@ __version__, ) -from .Rocketstore import Rocketstore, _ORDER, _ORDER_DESC, _ORDERBY_TIME, _LOCK, _DELETE, _KEYS, _COUNT, _ADD_AUTO_INC, _ADD_GUID, _FORMAT_JSON, _FORMAT_NATIVE, _FORMAT_XML, _FORMAT_PHP +from .Rocketstore import Rocketstore diff --git a/src/Rocketstore/__version__.py b/src/Rocketstore/__version__.py index 3ff7015..4729e9d 100644 --- a/src/Rocketstore/__version__.py +++ b/src/Rocketstore/__version__.py @@ -8,11 +8,11 @@ Desc: Versions """ -__title__ = "RocketStore" +__title__ = "Rocketstore" __description__ = "Rocket Store (Python) - Fast and Simple Database" __url__ = "https://github.com/klich3/rocket-store-python" -__version__ = "0.0.6" -__build__ = 0x000022 +__version__ = "0.0.7" +__build__ = 0x000029 __author__ = "Anton Sychev" __author_email__ = "anton@sychev.xyz" __copyright__ = "Copyright Simon Riget" diff --git a/src/Rocketstore/example.py b/src/Rocketstore/example.py deleted file mode 100644 index 2d80a59..0000000 --- a/src/Rocketstore/example.py +++ /dev/null @@ -1,107 +0,0 @@ -""" -█▀ █▄█ █▀▀ █░█ █▀▀ █░█ -▄█ ░█░ █▄▄ █▀█ ██▄ ▀▄▀ - -Author: (anton at sychev dot xyz) -sample.py (c) 2023 -Created: 2023-12-01 01:02:01 -Desc: sample create instance of RocketStore -Docs: documentation -""" - -from .Rocketstore import Rocketstore, _FORMAT_JSON, _FORMAT_NATIVE, _FORMAT_XML, _ADD_AUTO_INC, _ORDER_DESC - -rs = Rocketstore(**{"data_storage_area": "./webapp", - "data_format": _FORMAT_JSON}) - -rs.post("cars", "Mercedes_Benz_GT_R", {"owner": "Lisa Simpson"}) - -print("GET: ", rs.get("cars", ""), "\n-----\n") -# GET: {'count': 1, 'key': ['Mercedes_Benz_GT_R'], 'result': [{'owner': 'Lisa Simpson'}]} - -rs.post("cars", "BMW_740li", {"owner": "Greg Onslow"}, _ADD_AUTO_INC) -rs.post("cars", "BMW_740li", {"owner": "Sam Wise"}, _ADD_AUTO_INC) -rs.post("cars", "BMW_740li", {"owner": "Bill Bo"}, _ADD_AUTO_INC) -# tienen que haber un BMW_740li - -print("GET ALL CARS: ", rs.get("cars", "*"), "\n-----\n") -''' -Get all records: - { - count: 2, - key: [ 'Mercedes_Benz_GT_R', 'BMW_740li' ], - result: [ { owner: 'Lisa Simpson' }, { owner: 'Bill Bo' } ] -} -''' - - -dataset = { - "Gregs_BMW_740li": {"owner": "Greg Onslow"}, - "Lisas_Mercedes_Benz_GT_R": {"owner": "Lisa Simpson"}, - "Bills_BMW_740li": {"owner": "Bill Bo"}, -} - -for i in dataset: - rs.post("cars", i, dataset[i]) - -print("GET BMW's: ", rs.get("cars", "*BMW*"), "\n-----\n") -''' -Get BMW's: - { - count: 3, - key: [ 'BMW_740li', 'Gregs_BMW_740li', 'Bills_BMW_740li' ], - result: [ - { owner: 'Bill Bo' }, - { owner: 'Greg Onslow' }, - { owner: 'Bill Bo' } - ] -} -''' - - -print("Get list ordered by alphabetically descending keys: ", - rs.get("cars", "", _ORDER_DESC), "\n-----\n") -''' -Get list ordered by alphabetically descending keys: - { - count: 5, - key: [ - 'Mercedes_Benz_GT_R', - 'BMW_740li', - 'Gregs_BMW_740li', - 'Lisas_Mercedes_Benz_GT_R', - 'Bills_BMW_740li' - ], - result: [ - { owner: 'Lisa Simpson' }, - { owner: 'Bill Bo' }, - { owner: 'Greg Onslow' }, - { owner: 'Lisa Simpson' }, - { owner: 'Bill Bo' } - ] -} -''' - -r = rs.delete("cars", "*Mercedes*") -print("Delete all Mercedes's: ", r, "\n-----\n") -'''' -Delete all Mercedes's: - { count: 2 } - -''' - -print("Return all cars: ", rs.get("cars", "*"), "\n-----\n") -''' -{ - count: 3, - key: [ 'BMW_740li', 'Gregs_BMW_740li', 'Bills_BMW_740li' ], - result: [ - { owner: 'Bill Bo' }, - { owner: 'Greg Onslow' }, - { owner: 'Bill Bo' } - ] -} -''' - - -print("Delete all records: ", rs.delete(), "\n-----\n") diff --git a/tests/test.py b/tests/test.py index e5a02ef..55cd6d5 100644 --- a/tests/test.py +++ b/tests/test.py @@ -14,11 +14,11 @@ import json from pathlib import PurePath -from Rocketstore import Rocketstore, _FORMAT_JSON, _FORMAT_NATIVE, _FORMAT_XML, _ADD_AUTO_INC, _ORDER_DESC, _ADD_GUID, _ORDER, _ORDERBY_TIME, _LOCK, _DELETE, _KEYS, _COUNT, _FORMAT_PHP +from Rocketstore import Rocketstore rs = Rocketstore(**{ "data_storage_area": "./tests/ddbb", - "data_format": _FORMAT_JSON + "data_format": Rocketstore._FORMAT_JSON }) @@ -45,17 +45,17 @@ def test_bad_data_format_option(self): # set_options_on_main_object rs.options(**{ "data_storage_area": "./", - "data_format": _FORMAT_NATIVE + "data_format": Rocketstore._FORMAT_NATIVE }) self.assertEqual(rs.data_storage_area, "./") - self.assertEqual(rs.data_format, _FORMAT_NATIVE) + self.assertEqual(rs.data_format, Rocketstore._FORMAT_NATIVE) # set_options_to_unwritable_directory with self.assertRaises(Exception): rs.options(**{ "data_storage_area": "/rsdb/sdgdf", - "data_format": _FORMAT_NATIVE + "data_format": Rocketstore._FORMAT_NATIVE }) rs.delete() @@ -63,7 +63,7 @@ def test_bad_data_format_option(self): def test_records(self): rs.options(**{ "data_storage_area": "./tests/ddbb", - "data_format": _FORMAT_JSON + "data_format": Rocketstore._FORMAT_JSON }) rs.delete() @@ -92,11 +92,11 @@ def test_records(self): # Post_a_record_with_empty_key self.assertEqual(rs.post("person", "", record), {'count': 1, 'key': '1'}) - self.assertEqual(rs.post("person", "key", record, _ADD_AUTO_INC), { + self.assertEqual(rs.post("person", "key", record, Rocketstore._ADD_AUTO_INC), { 'count': 1, 'key': '2-key'}) # Post_a_record_with_auto_incremented_key_only - self.assertEqual(rs.post("person", "", record, _ADD_AUTO_INC), { + self.assertEqual(rs.post("person", "", record, Rocketstore._ADD_AUTO_INC), { "key": "3", "count": 1, }) @@ -110,13 +110,13 @@ def test_records(self): rs.post("\x00./.\x00", "bad", record) # Post_a_record_with_GUID_added_to_key - self.assertEqual(rs.post("person", "key-value", record, _ADD_AUTO_INC), { + self.assertEqual(rs.post("person", "key-value", record, Rocketstore._ADD_AUTO_INC), { "key": "4-key-value", "count": 1, }) # Post_a_record_with_GUID_key_only - res = rs.post("person", "", record, _ADD_GUID) + res = rs.post("person", "", record, Rocketstore._ADD_GUID) res = json.dumps(res) pattern = r'"key": "([^"]+)", "count": 1' self.assertRegex(res, pattern) @@ -199,24 +199,25 @@ def test_records(self): rs.post("person", "p2", 2) rs.post("person", "p3", 3) - order = rs.get("person", "p?", _ORDER) + order = rs.get("person", "p?", Rocketstore._ORDER) # Get order ascending self.assertEqual(order["result"], [1, 2, 3, 4]) # get keys - self.assertEqual(rs.get("person", "p?", _KEYS), { + self.assertEqual(rs.get("person", "p?", Rocketstore._KEYS), { 'count': 4, 'key': ['p1', 'p4', 'p2', 'p3']}) # Get keys in descending order - result = rs.get("person", "p?", _ORDER_DESC | _KEYS) + result = rs.get( + "person", "p?", Rocketstore._ORDER_DESC | Rocketstore._KEYS) self.assertEqual(result["key"], ["p4", "p3", "p2", "p1"]) # Get keys in ascending order - result = rs.get("person", "p?", _ORDER | _KEYS) + result = rs.get("person", "p?", Rocketstore._ORDER | Rocketstore._KEYS) self.assertEqual(result["key"], ["p1", "p2", "p3", "p4"]) # get record count - self.assertEqual(rs.get("person", "p?", _COUNT), { + self.assertEqual(rs.get("person", "p?", Rocketstore._COUNT), { "count": 4, })