# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['dictdatabase']

package_data = \
{'': ['*']}

install_requires = \
['orjson>=3.8.0,<4.0.0']

setup_kwargs = {
    'name': 'dictdatabase',
    'version': '2.0.5',
    'description': 'Easy-to-use database using dicts',
    'long_description': '![Logo](https://github.com/mkrd/DictDataBase/blob/master/assets/logo.png?raw=true)\n\n[![Downloads](https://pepy.tech/badge/dictdatabase)](https://pepy.tech/project/dictdatabase)\n[![Downloads](https://pepy.tech/badge/dictdatabase/month)](https://pepy.tech/project/dictdatabase)\n[![Downloads](https://pepy.tech/badge/dictdatabase/week)](https://pepy.tech/project/dictdatabase)\n![Tests](https://github.com/mkrd/DictDataBase/actions/workflows/test.yml/badge.svg)\n![Coverage](https://github.com/mkrd/DictDataBase/blob/master/assets/coverage.svg?raw=1)\n\nDictDataBase is a simple and fast database for handling json or compressed json as the underlying storage mechanism. Features:\n- **Multi threading and multi processing safe**. Multiple processes on the same machine can simultaneously read and write to dicts without losing data.\n- **ACID** compliant. Unlike TinyDB, it is suited for concurrent environments.\n- **No database server** required. Simply import DictDataBase in your project and use it.\n- **Compression**. Configure if the files should be stored as raw json or as json compressed with zlib.\n- **Fast**. A dict can be accessed partially without having to parse the entire file, making the read and writes very efficient.\n- **Tested** with over 400 test cases.\n\n### Why use DictDataBase\n- For example, have a webserver dispatch database reads and writes concurrently.\n- If spinning up a database server is an overkill for your application.\n    - But you need [ACID](https://en.wikipedia.org/wiki/ACID) guarantees.\n- You have a big database but only want to access single key-value pairs repeatedly. DictDataBase can do this efficiently and quickly.\n- Your use case is suited for working with json data, or you have to work with a lot of json data.\n\n### Why not DictDataBase\n- If you need document indexes.\n- If a relational database is better suited for your use case.\n\n## Install\n\n```sh\npip install dictdatabase\n```\n\n\n# Configuration\nThere are 5 configuration options:\n\n### Storage directory\nSet storage_directory to the path of the directory that will contain your json files:\n```python\nDDB.config.storage_directory = "./ddb_storage" # Default value\n```\n\n### Compression\nIf you want to use compressed files, set use_compression to `True`.\nThis will make the db files significantly smaller and might improve performance if your disk is slow.\nHowever, the files will not be human readable.\n```python\nDDB.config.use_compression = False # Default value\n```\n\n### Indentation\nSet the way how written json files should be indented. Behaves exactly like `json.dumps(indent=...)`.\nIt can be an `int` for the number of spaces, the tab character, or `None` if you don\'t want the files to be indented.\n```python\nDDB.config.indent = "\\t" # Default value\n```\n\n### Sort keys\nSpecify if you want the dict keys to be sorted when writing to a file. Behaves exactly like `json.dumps(sort_keys=...)`.\n```python\nDDB.config.sort_keys = True # Default value\n```\n\n### Use orjson\nYou can use the orjson encoder and decoder if you need to.\nThe standard library json module is sufficient most of the time.\nHowever, orjson is a lot more performant in virtually all cases.\n```python\nDDB.config.use_orjson = True # Default value\n```\n\n\n# Usage\n\n## Import\n\n```python\nimport dictdatabase as DDB\n```\n\n\n## Create dict\nThis library is called DictDataBase, but you can actually use any json serializable object.\n```python\nuser_data_dict = {\n    "users": {\n        "Ben": { "age": 30, "job": "Software Engineer" },\n        "Sue": { "age": 21, "job": "Architect" },\n        "Joe": { "age": 50, "job": "Manager" }\n    },\n    "follows": [["Ben", "Sue"], ["Joe", "Ben"]]\n}\nDDB.at("users").create(user_data_dict)\n\n# There is now a file called users.json (or user_data.ddb if you use compression)\n# in your specified storage directory.\n```\n\n## Check if file or sub-key exists\n```python\nDDB.at("users").exists()  # True\nDDB.at("users").exists("Ben")  # True\nDDB.at("users").exists("Sam")  # False\n```\n\n## Read dicts\n```python\nd = DDB.at("users").read()\n# You now have a copy of the json file named "users"\nd == user_data_dict # True\n\n# Only partially read Joe\njoe = DDB.at("users").read("Joe")\njoe == user_data_dict["Joe"] # True\n```\n\n## Write dicts\n```python\nwith DDB.at("users").session() as (session, users):\n    # You now have a copy of the json file users as the variable users\n    # Inside the with statement, the file of user_data will be locked, and no other\n    # processes will be able to interfere.\n    users["follows"].append(["Sue", "Ben"])\n    session.write()\n    # session.write() must be called to save the changes!\nprint(DDB.at("user_data").read()["follows"])\n>>> [["Ben", "Sue"], ["Joe", "Ben"], ["Sue", "Ben"]]\n```\n\nIf you do not call session.write(), changes will not be written to disk!\n\n\n## Partial reading and writing\nImagine you have a huge json file with many transactions.\nThe json file looks like this: `{<id>: <transaction>, <id>: <transaction>, ...}`.\nNormally, you would have to read and parse the entire file to get a specific key.\nAfter modifying the transaction, you would also have to serialize and write the entire file again.\nWith DDB, you can do it more efficiently:\n```python\nwith DDB.at("transactions").session(key="134425") as (session, transaction):\n    transaction["status"] = "cancelled"\n    session.write()\n```\nAfterwards, the status is updated in the json file.\nHowever, DDB did only efficiently gather the one transaction with id 134425, parsed its value, and serialized that value alone before writing again.\nThis is several orders of magnitude faster than the naive approach when working with big files.\n\n\n# Performance\nIn preliminary testing, DictDataBase showed promising performance.\n\n### SQLite vs DictDataBase\nIn each case, `16` parallel processes were spawned to perform `128` increments of a counter in `4` tables/files.\nSQLite achieves `2435 operations/s` while DictDataBase managed to achieve `3143 operations/s`.\n\n### More tests\nIt remains to be tested how DictDatabase performs in different scenarios, for example when multiple processes want to perform full writes to one big file.\n\n\n# API Reference\n\n### `at(pattern) -> DDBMethodChooser`\n`pattern` can be multiple parameters, which will be joined with a "`/"` to a path.\nThe file at the given path is then selected, and further operations can be performed using the `DDBMethodChooser`\n\n## DDBMethodChooser\n\n### `exists(key: str = None) -> bool`\nEfficiently checks if a database exists.\nIf it contains a wildcard, it will return True if at least one exists.\nIf the key is passed, check if it exists in a database.\nThe key can be anywhere in the database, even deeply nested.\nAs long it exists as a key in any dict, it will be found.\n\n### `create(db=None, force_overwrite=False)`\nIt creates a database file at the given path, and writes the given database to\nit\n:param db: The database to create. If not specified, an empty database is\ncreated.\n:param force_overwrite: If True, will overwrite the database if it already\nexists, defaults to False (optional).\n\n### `delete()`\nDelete the database at the selected path.\n\n### `read(key: str = None, as_type=None) -> dict | Any`\nReads a database and returns it. If a key is given, return the value at that key, more info in Args.\n\nArgs:\n- `key`: If provided, only return the value of the given key. The key\n    can be anywhere in the database, even deeply nested. If multiple\n    identical keys exist, the one at the outermost indentation will\n    be returned. This is very fast, as it does not read the entire\n    database, but only the key - value pair.\n- `as_type`: If provided, return the value as the given type. Eg. as=str will return str(value).\n\n### `session(key: str = None, as_type=None) -> DDBSession | DDBMultiSession | DDBSubSession`\nOpen multiple files at once using a glob pattern, like "user/*".\nMultiple arguments are allowed to access folders,\nso session(f"users/{user_id}") is equivalent\nto session("users", user_id).\n',
    'author': 'Marcel Kröker',
    'author_email': 'kroeker.marcel@gmail.com',
    'maintainer': 'None',
    'maintainer_email': 'None',
    'url': 'https://github.com/mkrd/DictDataBase',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'python_requires': '>=3.8,<4.0',
}


setup(**setup_kwargs)
