simple-graph-libsql


Namesimple-graph-libsql JSON
Version 2.1.0 PyPI version JSON
download
home_page
SummaryA simple graph database in LibSQL
upload_time2024-03-16 12:51:12
maintainer
docs_urlNone
authorYour Name
requires_python>=3.8,<4.0
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Simple GraphDB
- [ ] Use [Pydantic](https://github.com/pydantic/pydantic)
- [ ] Add [Knowledge Graph abstraction](https://jxnl.github.io/instructor/examples/knowledge_graph/#defining-the-structures)
- [ ] Use [Instructor](https://github.com/jxnl/instructor/) to provide easy LLM interaction

---

# Original README

This is the [PyPI](https://pypi.org/) package of the [simple-graph](https://github.com/dpapathanasiou/simple-graph/blob/main/python) implementation in [Python](https://www.python.org/), which is a simple [graph database](https://en.wikipedia.org/wiki/Graph_database) in [libsql](https://github.com/tursodatabase/libsql).

## Build and Test

How to [generate the distribution archive](https://packaging.python.org/tutorials/packaging-projects/#generating-distribution-archives) and confirm it on [test.pypi.org](https://packaging.python.org/tutorials/packaging-projects/#uploading-the-distribution-archives), also based on the [pypa/sampleproject](https://github.com/pypa/sampleproject):

```sh
rm -rf build dist src/simple_graph_libsql.egg-info
poetry build
poetry publish --repository testpypi
```

Create a poetry environment, activate it, install all the requirements, and confirm the package is available:

```sh
$ poetry shell
$ poetry install --no-root
$ python
Python 3.6.13 |Anaconda, Inc.| (default, Jun  4 2021, 14:25:59) 
[GCC 7.5.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from simple_graph_libsql import database as db
```

With the package installed, update `PYTHONPATH` to include `./tests` and run `pytest` from the root of this repository. If the tests pass, rebuild and push to [pypi.org](https://pypi.org):

```sh
rm -rf build dist src/simple_graph_libsql.egg-info
poetry build
poetry publish
```

# Structure

The [schema](https://github.com/dpapathanasiou/simple-graph/tree/main/sql/schema.sql) consists of just two structures:

* Nodes - these are any [json](https://www.json.org/) objects, with the only constraint being that they each contain a unique `id` value
* Edges - these are pairs of node `id` values, specifying the direction, with an optional json object as connection properties

There are also traversal functions as native SQLite [Common Table Expressions](https://www.sqlite.org/lang_with.html):

* [Both directions](https://github.com/dpapathanasiou/simple-graph/tree/main/sql/traverse.sql)
* [Inbound](https://github.com/dpapathanasiou/simple-graph/tree/main/sql/traverse-inbound.sql)
* [Outbound](https://github.com/dpapathanasiou/simple-graph/tree/main/sql/traverse-outbound.sql)

# Applications

* [Social networks](https://en.wikipedia.org/wiki/Social_graph)
* [Interest maps/recommendation finders](https://en.wikipedia.org/wiki/Interest_graph)
* [To-do / task lists](https://en.wikipedia.org/wiki/Task_list)
* [Bug trackers](https://en.wikipedia.org/wiki/Open-source_software_development#Bug_trackers_and_task_lists)
* [Customer relationship management (CRM)](https://en.wikipedia.org/wiki/Customer_relationship_management)
* [Gantt chart](https://en.wikipedia.org/wiki/Gantt_chart)

# Usage

## Installation Requirements

* [LibSQL](https://github.com/tursodatabase/libsql), version 0.0.26 or higher.
* [Graphviz](https://graphviz.org/) for visualization ([download page](https://www.graphviz.org/download/), [installation procedure for Windows](https://forum.graphviz.org/t/new-simplified-installation-procedure-on-windows/224))
* [Jinja2](https://pypi.org/project/Jinja2/) for the search and traversal templates

## Basic Functions

The [database script](src/simple_graph_libsql/database.py) provides convenience functions for [atomic transactions](https://en.wikipedia.org/wiki/Atomicity_(database_systems)) to add, delete, connect, and search for nodes.

Any single node or path of nodes can also be depicted graphically by using the `visualize` function within the database script to generate [dot](https://graphviz.org/doc/info/lang.html) files, which in turn can be converted to images with Graphviz.

### Example

Dropping into a python shell, we can create, [upsert](https://en.wiktionary.org/wiki/upsert), and connect people from the early days of [Apple Computer](https://en.wikipedia.org/wiki/Apple_Inc.).
It needs database url(db_url) and authentication token(auth_token) to connecti with remote database:

```
>>> from simple_graph_libsql import database as db
>>> db.initialize(db_url, auth_token)
>>> db.atomic(db_url, auth_token, db.add_node({'name': 'Apple Computer Company', 'type':['company', 'start-up'], 'founded': 'April 1, 1976'}, 1))
>>> db.atomic(db_url, auth_token, db.add_node({'name': 'Steve Wozniak', 'type':['person','engineer','founder']}, 2))
>>> db.atomic(db_url, auth_token, db.add_node({'name': 'Steve Jobs', 'type':['person','designer','founder']}, 3))
>>> db.atomic(db_url, auth_token, db.add_node({'name': 'Ronald Wayne', 'type':['person','administrator','founder']}, 4))
>>> db.atomic(db_url, auth_token, db.add_node({'name': 'Mike Markkula', 'type':['person','investor']}, 5))
>>> db.atomic(db_url, auth_token, db.connect_nodes(2, 1, {'action': 'founded'}))
>>> db.atomic(db_url, auth_token, db.connect_nodes(3, 1, {'action': 'founded'}))
>>> db.atomic(db_url, auth_token, db.connect_nodes(4, 1, {'action': 'founded'}))
>>> db.atomic(db_url, auth_token, db.connect_nodes(5, 1, {'action': 'invested', 'equity': 80000, 'debt': 170000}))
>>> db.atomic(db_url, auth_token, db.connect_nodes(1, 4, {'action': 'divested', 'amount': 800, 'date': 'April 12, 1976'}))
>>> db.atomic(db_url, auth_token,  db.connect_nodes(2, 3))
>>> db.atomic(db_url, auth_token, db.upsert_node(2, {'nickname': 'Woz'}))
```

There are also bulk operations, to insert and connect lists of nodes in one transaction.

The nodes can be searched by their ids:

```
>>> db.atomic(db_url, auth_token, db.find_node(1))
{'name': 'Apple Computer Company', 'type': ['company', 'start-up'], 'founded': 'April 1, 1976', 'id': 1}
```

Searches can also use combinations of other attributes, both as strict equality, or using `LIKE` in combination with a trailing `%` for "starts with" or `%` at both ends for "contains":

```
>>> db.atomic(db_url, auth_token, db.find_nodes([db._generate_clause('name', predicate='LIKE')], ('Steve%',)))
[{'name': 'Steve Wozniak', 'type': ['person', 'engineer', 'founder'], 'id': 2, 'nickname': 'Woz'}, {'name': 'Steve Jobs', 'type': ['person', 'designer', 'founder'], 'id': 3}]
>>> db.atomic(db_url, auth_token, db.find_nodes([db._generate_clause('name', predicate='LIKE'), db._generate_clause('name', predicate='LIKE', joiner='OR')], ('%Woz%', '%Markkula',)))
[{'name': 'Steve Wozniak', 'type': ['person', 'engineer', 'founder'], 'id': 2, 'nickname': 'Woz'}, {'name': 'Mike Markkula', 'type': ['person', 'investor'], 'id': 5}]
```

More complex queries to introspect the json body, using the [sqlite json_tree() function](https://www.sqlite.org/json1.html), are also possible, such as this query for every node whose `type` array contains the value `founder`:

```
>>> db.atomic(db_url, auth_token,  db.find_nodes([db._generate_clause('type', tree=True)], ('founder',), tree_query=True, key='type'))
[{'name': 'Steve Wozniak', 'type': ['person', 'engineer', 'founder'], 'id': 2, 'nickname': 'Woz'}, {'name': 'Steve Jobs', 'type': ['person', 'designer', 'founder'], 'id': 3}, {'name': 'Ronald Wayne', 'type': ['person', 'administrator', 'founder'], 'id': 4}]
```

See the `_generate_clause()` and `_generate_query()` functions in [database.py](src/simple_graph_libsql/database.py) for usage hints.

Paths through the graph can be discovered with a starting node id, and an optional ending id; the default neighbor expansion is nodes connected nodes in either direction, but that can changed by specifying either `find_outbound_neighbors` or `find_inbound_neighbors` instead:

```
>>> db.traverse(db_url, auth_token, 2, 3)
['2', '1', '3']
>>> db.traverse(db_url, auth_token, 4, 5)
['4', '1', '2', '3', '5']
>>> db.traverse(db_url, auth_token, 5, neighbors_fn=db.find_inbound_neighbors)
['5']
>>> db.traverse(db_url, auth_token, 5, neighbors_fn=db.find_outbound_neighbors)
['5', '1', '4']
>>> db.traverse(db_url, auth_token, 5, neighbors_fn=db.find_neighbors)
['5', '1', '2', '3', '4']
```

Any path or list of nodes can rendered graphically by using the `visualize` function. This command produces [dot](https://graphviz.org/doc/info/lang.html) files, which are also rendered as images with Graphviz:

```
>>> from visualizers import graphviz_visualize
>>> graphviz_visualize(db_url, auth_token, 'apple.dot', [4, 1, 5])
```

The [resulting text file](tests/fixtures/apple-raw.dot) also comes with an associated image (the default is [png](https://en.wikipedia.org/wiki/Portable_Network_Graphics), but that can be changed by supplying a different value to the `format` parameter)

The default options include every key/value pair (excluding the id) in the node and edge objects, and there are display options to help refine what is produced:

```
>>> graphviz_visualize(db_url, auth_token, 'apple.dot', [4, 1, 5], exclude_node_keys=['type'], hide_edge_key=True)
>>> path_with_bodies = db.traverse(db_url, auth_token, source, target, with_bodies=True) 
>>>graphviz_visualize_bodies('apple.dot', path_with_bodies)
```

The [resulting dot file](tests/fixtures/apple.dot) can be edited further as needed; the [dot guide](https://graphviz.org/pdf/dotguide.pdf) has more options and examples.

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "simple-graph-libsql",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8,<4.0",
    "maintainer_email": "",
    "keywords": "",
    "author": "Your Name",
    "author_email": "you@example.com",
    "download_url": "https://files.pythonhosted.org/packages/21/3c/3c0252261f786a59f27bc4b20a5f0f8fb20249e254a8e30f630552737cc3/simple_graph_libsql-2.1.0.tar.gz",
    "platform": null,
    "description": "# Simple GraphDB\n- [ ] Use [Pydantic](https://github.com/pydantic/pydantic)\n- [ ] Add [Knowledge Graph abstraction](https://jxnl.github.io/instructor/examples/knowledge_graph/#defining-the-structures)\n- [ ] Use [Instructor](https://github.com/jxnl/instructor/) to provide easy LLM interaction\n\n---\n\n# Original README\n\nThis is the [PyPI](https://pypi.org/) package of the [simple-graph](https://github.com/dpapathanasiou/simple-graph/blob/main/python) implementation in [Python](https://www.python.org/), which is a simple [graph database](https://en.wikipedia.org/wiki/Graph_database) in [libsql](https://github.com/tursodatabase/libsql).\n\n## Build and Test\n\nHow to [generate the distribution archive](https://packaging.python.org/tutorials/packaging-projects/#generating-distribution-archives) and confirm it on [test.pypi.org](https://packaging.python.org/tutorials/packaging-projects/#uploading-the-distribution-archives), also based on the [pypa/sampleproject](https://github.com/pypa/sampleproject):\n\n```sh\nrm -rf build dist src/simple_graph_libsql.egg-info\npoetry build\npoetry publish --repository testpypi\n```\n\nCreate a poetry environment, activate it, install all the requirements, and confirm the package is available:\n\n```sh\n$ poetry shell\n$ poetry install --no-root\n$ python\nPython 3.6.13 |Anaconda, Inc.| (default, Jun  4 2021, 14:25:59) \n[GCC 7.5.0] on linux\nType \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n>>> from simple_graph_libsql import database as db\n```\n\nWith the package installed, update `PYTHONPATH` to include `./tests` and run `pytest` from the root of this repository. If the tests pass, rebuild and push to [pypi.org](https://pypi.org):\n\n```sh\nrm -rf build dist src/simple_graph_libsql.egg-info\npoetry build\npoetry publish\n```\n\n# Structure\n\nThe [schema](https://github.com/dpapathanasiou/simple-graph/tree/main/sql/schema.sql) consists of just two structures:\n\n* Nodes - these are any [json](https://www.json.org/) objects, with the only constraint being that they each contain a unique `id` value\n* Edges - these are pairs of node `id` values, specifying the direction, with an optional json object as connection properties\n\nThere are also traversal functions as native SQLite [Common Table Expressions](https://www.sqlite.org/lang_with.html):\n\n* [Both directions](https://github.com/dpapathanasiou/simple-graph/tree/main/sql/traverse.sql)\n* [Inbound](https://github.com/dpapathanasiou/simple-graph/tree/main/sql/traverse-inbound.sql)\n* [Outbound](https://github.com/dpapathanasiou/simple-graph/tree/main/sql/traverse-outbound.sql)\n\n# Applications\n\n* [Social networks](https://en.wikipedia.org/wiki/Social_graph)\n* [Interest maps/recommendation finders](https://en.wikipedia.org/wiki/Interest_graph)\n* [To-do / task lists](https://en.wikipedia.org/wiki/Task_list)\n* [Bug trackers](https://en.wikipedia.org/wiki/Open-source_software_development#Bug_trackers_and_task_lists)\n* [Customer relationship management (CRM)](https://en.wikipedia.org/wiki/Customer_relationship_management)\n* [Gantt chart](https://en.wikipedia.org/wiki/Gantt_chart)\n\n# Usage\n\n## Installation Requirements\n\n* [LibSQL](https://github.com/tursodatabase/libsql), version 0.0.26 or higher.\n* [Graphviz](https://graphviz.org/) for visualization ([download page](https://www.graphviz.org/download/), [installation procedure for Windows](https://forum.graphviz.org/t/new-simplified-installation-procedure-on-windows/224))\n* [Jinja2](https://pypi.org/project/Jinja2/) for the search and traversal templates\n\n## Basic Functions\n\nThe [database script](src/simple_graph_libsql/database.py) provides convenience functions for [atomic transactions](https://en.wikipedia.org/wiki/Atomicity_(database_systems)) to add, delete, connect, and search for nodes.\n\nAny single node or path of nodes can also be depicted graphically by using the `visualize` function within the database script to generate [dot](https://graphviz.org/doc/info/lang.html) files, which in turn can be converted to images with Graphviz.\n\n### Example\n\nDropping into a python shell, we can create, [upsert](https://en.wiktionary.org/wiki/upsert), and connect people from the early days of [Apple Computer](https://en.wikipedia.org/wiki/Apple_Inc.).\nIt needs database url(db_url) and authentication token(auth_token) to connecti with remote database:\n\n```\n>>> from simple_graph_libsql import database as db\n>>> db.initialize(db_url, auth_token)\n>>> db.atomic(db_url, auth_token, db.add_node({'name': 'Apple Computer Company', 'type':['company', 'start-up'], 'founded': 'April 1, 1976'}, 1))\n>>> db.atomic(db_url, auth_token, db.add_node({'name': 'Steve Wozniak', 'type':['person','engineer','founder']}, 2))\n>>> db.atomic(db_url, auth_token, db.add_node({'name': 'Steve Jobs', 'type':['person','designer','founder']}, 3))\n>>> db.atomic(db_url, auth_token, db.add_node({'name': 'Ronald Wayne', 'type':['person','administrator','founder']}, 4))\n>>> db.atomic(db_url, auth_token, db.add_node({'name': 'Mike Markkula', 'type':['person','investor']}, 5))\n>>> db.atomic(db_url, auth_token, db.connect_nodes(2, 1, {'action': 'founded'}))\n>>> db.atomic(db_url, auth_token, db.connect_nodes(3, 1, {'action': 'founded'}))\n>>> db.atomic(db_url, auth_token, db.connect_nodes(4, 1, {'action': 'founded'}))\n>>> db.atomic(db_url, auth_token, db.connect_nodes(5, 1, {'action': 'invested', 'equity': 80000, 'debt': 170000}))\n>>> db.atomic(db_url, auth_token, db.connect_nodes(1, 4, {'action': 'divested', 'amount': 800, 'date': 'April 12, 1976'}))\n>>> db.atomic(db_url, auth_token,  db.connect_nodes(2, 3))\n>>> db.atomic(db_url, auth_token, db.upsert_node(2, {'nickname': 'Woz'}))\n```\n\nThere are also bulk operations, to insert and connect lists of nodes in one transaction.\n\nThe nodes can be searched by their ids:\n\n```\n>>> db.atomic(db_url, auth_token, db.find_node(1))\n{'name': 'Apple Computer Company', 'type': ['company', 'start-up'], 'founded': 'April 1, 1976', 'id': 1}\n```\n\nSearches can also use combinations of other attributes, both as strict equality, or using `LIKE` in combination with a trailing `%` for \"starts with\" or `%` at both ends for \"contains\":\n\n```\n>>> db.atomic(db_url, auth_token, db.find_nodes([db._generate_clause('name', predicate='LIKE')], ('Steve%',)))\n[{'name': 'Steve Wozniak', 'type': ['person', 'engineer', 'founder'], 'id': 2, 'nickname': 'Woz'}, {'name': 'Steve Jobs', 'type': ['person', 'designer', 'founder'], 'id': 3}]\n>>> db.atomic(db_url, auth_token, db.find_nodes([db._generate_clause('name', predicate='LIKE'), db._generate_clause('name', predicate='LIKE', joiner='OR')], ('%Woz%', '%Markkula',)))\n[{'name': 'Steve Wozniak', 'type': ['person', 'engineer', 'founder'], 'id': 2, 'nickname': 'Woz'}, {'name': 'Mike Markkula', 'type': ['person', 'investor'], 'id': 5}]\n```\n\nMore complex queries to introspect the json body, using the [sqlite json_tree() function](https://www.sqlite.org/json1.html), are also possible, such as this query for every node whose `type` array contains the value `founder`:\n\n```\n>>> db.atomic(db_url, auth_token,  db.find_nodes([db._generate_clause('type', tree=True)], ('founder',), tree_query=True, key='type'))\n[{'name': 'Steve Wozniak', 'type': ['person', 'engineer', 'founder'], 'id': 2, 'nickname': 'Woz'}, {'name': 'Steve Jobs', 'type': ['person', 'designer', 'founder'], 'id': 3}, {'name': 'Ronald Wayne', 'type': ['person', 'administrator', 'founder'], 'id': 4}]\n```\n\nSee the `_generate_clause()` and `_generate_query()` functions in [database.py](src/simple_graph_libsql/database.py) for usage hints.\n\nPaths through the graph can be discovered with a starting node id, and an optional ending id; the default neighbor expansion is nodes connected nodes in either direction, but that can changed by specifying either `find_outbound_neighbors` or `find_inbound_neighbors` instead:\n\n```\n>>> db.traverse(db_url, auth_token, 2, 3)\n['2', '1', '3']\n>>> db.traverse(db_url, auth_token, 4, 5)\n['4', '1', '2', '3', '5']\n>>> db.traverse(db_url, auth_token, 5, neighbors_fn=db.find_inbound_neighbors)\n['5']\n>>> db.traverse(db_url, auth_token, 5, neighbors_fn=db.find_outbound_neighbors)\n['5', '1', '4']\n>>> db.traverse(db_url, auth_token, 5, neighbors_fn=db.find_neighbors)\n['5', '1', '2', '3', '4']\n```\n\nAny path or list of nodes can rendered graphically by using the `visualize` function. This command produces [dot](https://graphviz.org/doc/info/lang.html) files, which are also rendered as images with Graphviz:\n\n```\n>>> from visualizers import graphviz_visualize\n>>> graphviz_visualize(db_url, auth_token, 'apple.dot', [4, 1, 5])\n```\n\nThe [resulting text file](tests/fixtures/apple-raw.dot) also comes with an associated image (the default is [png](https://en.wikipedia.org/wiki/Portable_Network_Graphics), but that can be changed by supplying a different value to the `format` parameter)\n\nThe default options include every key/value pair (excluding the id) in the node and edge objects, and there are display options to help refine what is produced:\n\n```\n>>> graphviz_visualize(db_url, auth_token, 'apple.dot', [4, 1, 5], exclude_node_keys=['type'], hide_edge_key=True)\n>>> path_with_bodies = db.traverse(db_url, auth_token, source, target, with_bodies=True) \n>>>graphviz_visualize_bodies('apple.dot', path_with_bodies)\n```\n\nThe [resulting dot file](tests/fixtures/apple.dot) can be edited further as needed; the [dot guide](https://graphviz.org/pdf/dotguide.pdf) has more options and examples.\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A simple graph database in LibSQL",
    "version": "2.1.0",
    "project_urls": null,
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "b814ed379a5f7619a6449fed2bf55b0a126f3cb545c45b2a6bdd2cfb61cd6c04",
                "md5": "3ce046ebe63755d5e42eee756b5ed3b6",
                "sha256": "22286c2b5d8bd9844627587e4f671b66702cb04f853ae8124ec34471ed8e656c"
            },
            "downloads": -1,
            "filename": "simple_graph_libsql-2.1.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "3ce046ebe63755d5e42eee756b5ed3b6",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8,<4.0",
            "size": 12399,
            "upload_time": "2024-03-16T12:51:09",
            "upload_time_iso_8601": "2024-03-16T12:51:09.675116Z",
            "url": "https://files.pythonhosted.org/packages/b8/14/ed379a5f7619a6449fed2bf55b0a126f3cb545c45b2a6bdd2cfb61cd6c04/simple_graph_libsql-2.1.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "213c3c0252261f786a59f27bc4b20a5f0f8fb20249e254a8e30f630552737cc3",
                "md5": "69f17bd83f967d19183458eb26eff56a",
                "sha256": "ef65b2a234d534dc3907436b1e6d9ec9a9964472972c03331460ff1c8cc02075"
            },
            "downloads": -1,
            "filename": "simple_graph_libsql-2.1.0.tar.gz",
            "has_sig": false,
            "md5_digest": "69f17bd83f967d19183458eb26eff56a",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8,<4.0",
            "size": 11973,
            "upload_time": "2024-03-16T12:51:12",
            "upload_time_iso_8601": "2024-03-16T12:51:12.056689Z",
            "url": "https://files.pythonhosted.org/packages/21/3c/3c0252261f786a59f27bc4b20a5f0f8fb20249e254a8e30f630552737cc3/simple_graph_libsql-2.1.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-03-16 12:51:12",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "simple-graph-libsql"
}
        
Elapsed time: 0.20487s