Skip to content
Open
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
17 changes: 17 additions & 0 deletions .codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
coverage:
status:
project:
default:
target: auto
threshold: 5%
patch:
default:
target: auto
threshold: 5%

ignore:
- "falkordb/embedded/*" # Embedded module requires external binaries (redis-server, falkordb.so)
- "examples/*"
- "tests/*"
- "docs/*"
- "setup.py" # Build script
16 changes: 16 additions & 0 deletions .github/wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,19 @@ html
https
www
faq
asyncio
ephemeral
psutil
lifecycle
unix
Redis
Cypher
gcc
setuptools
Ubuntu
Debian
macOS
xcode
urllib
tarfile
submodule
10 changes: 9 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
venv
__pycache__
poetry.lock
poetry.lock

# Embedded build artifacts
redis.submodule/
falkordb.so
falkordb/bin/
build/
dist/
*.egg-info/
16 changes: 16 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
include README.md
include LICENSE
include pyproject.toml
include setup.py

# Include binaries for embedded mode
recursive-include falkordb/bin *
include falkordb.so

# Include embedded module
recursive-include falkordb/embedded *.py

# Exclude build artifacts
global-exclude *.pyc
global-exclude __pycache__
global-exclude .DS_Store
83 changes: 82 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,24 @@ see [docs](http://falkordb-py.readthedocs.io/)
pip install FalkorDB
```

To install with embedded FalkorDB support (includes Redis and FalkorDB binaries):
```sh
pip install FalkorDB[embedded]
```

The embedded installation automatically:
- Downloads Redis source code
- Compiles Redis from source
- Downloads the FalkorDB module binary for your architecture
- Packages everything with the Python client

**Note**: Embedded installation requires build tools (`gcc`, `make`) to be installed on your system.

To skip building embedded binaries (faster install for non-embedded usage):
```sh
FALKORDB_SKIP_EMBEDDED=1 pip install FalkorDB
```

## Usage

### Run FalkorDB instance
Expand All @@ -27,7 +45,20 @@ docker run --rm -p 6379:6379 falkordb/falkordb
```
Or use [FalkorDB Cloud](https://app.falkordb.cloud)

### Synchronous Example
Or use embedded FalkorDB (no external server needed):
```python
from falkordb import FalkorDB

# Create an embedded FalkorDB instance
# Requires: pip install FalkorDB[embedded]
db = FalkorDB(embedded=True)

# Use it just like a remote connection
g = db.select_graph('social')
result = g.query("CREATE (n:Person {name: 'Alice'}) RETURN n")
```

### Synchronous Example

```python
from falkordb import FalkorDB
Expand Down Expand Up @@ -97,3 +128,53 @@ async def main():
if __name__ == "__main__":
asyncio.run(main())
```

### Embedded FalkorDB

FalkorDB supports an embedded mode that runs Redis + FalkorDB in a local process, eliminating the need for a separate server. This is useful for development, testing, or applications that need a self-contained graph database.

**Installation:**

The embedded installation automatically downloads, compiles, and packages Redis and the FalkorDB module:

```sh
pip install FalkorDB[embedded]
```

**Prerequisites:**
- Build tools: `gcc`, `make` (for compiling Redis)
- Python development headers
- On Ubuntu/Debian: `sudo apt-get install build-essential`
- On macOS: Xcode Command Line Tools (`xcode-select --install`)

**Note:** The build process happens automatically during installation and may take a few minutes to compile Redis.

**Usage:**
```python
from falkordb import FalkorDB

# Create an embedded instance (data stored in memory)
db = FalkorDB(embedded=True)

# Or specify a database file for persistence
db = FalkorDB(embedded=True, dbfilename='/path/to/database.db')

# Use it exactly like a remote FalkorDB instance
graph = db.select_graph('my_graph')
result = graph.query('CREATE (n:Person {name: "John", age: 30}) RETURN n')

# Data persists across connections when using dbfilename
del db

# Reconnect to the same database
db = FalkorDB(embedded=True, dbfilename='/path/to/database.db')
graph = db.select_graph('my_graph')
result = graph.query('MATCH (n:Person) RETURN n.name, n.age')
```

**Notes:**
- Embedded mode uses Unix sockets for communication (no network overhead)
- The embedded server automatically starts and stops with your application
- Embedded mode is not available with asyncio (use the synchronous API)
- For production deployments, use a standalone FalkorDB server or FalkorDB Cloud
```
136 changes: 136 additions & 0 deletions examples/embedded_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#!/usr/bin/env python
"""
Example of using FalkorDB in embedded mode.

This example shows how to use FalkorDB without needing a separate server.
The embedded mode automatically starts a Redis+FalkorDB process that runs
locally and communicates via Unix socket.

Requirements:
pip install falkordb[embedded]

Note: Embedded mode is only available for synchronous code, not asyncio.
"""

from falkordb import FalkorDB


def main():
print("=== FalkorDB Embedded Example ===\n")

# Create an embedded FalkorDB instance
# Data will be stored in memory (ephemeral)
print("1. Creating embedded FalkorDB instance...")
db = FalkorDB(embedded=True)
print(" ✓ Embedded FalkorDB started\n")

# Select a graph
print("2. Selecting a graph...")
graph = db.select_graph('social')
print(" ✓ Graph 'social' selected\n")

# Create some nodes and relationships
print("3. Creating nodes and relationships...")
graph.query("""
CREATE
(alice:Person {name: 'Alice', age: 30}),
(bob:Person {name: 'Bob', age: 35}),
(charlie:Person {name: 'Charlie', age: 28}),
(alice)-[:KNOWS]->(bob),
(bob)-[:KNOWS]->(charlie),
(charlie)-[:KNOWS]->(alice)
""")
print(" ✓ Created 3 people and their relationships\n")

# Query the data
print("4. Querying the data...")
result = graph.query("MATCH (p:Person) RETURN p.name, p.age ORDER BY p.age")
print(" People in the graph:")
for row in result.result_set:
name, age = row
print(f" - {name}, age {age}")
print()

# Find connections
print("5. Finding connections...")
result = graph.query("""
MATCH (a:Person)-[:KNOWS]->(b:Person)
RETURN a.name, b.name
""")
print(" Relationships:")
for row in result.result_set:
person1, person2 = row
print(f" - {person1} knows {person2}")
print()

# List all graphs
print("6. Listing all graphs...")
graphs = db.list_graphs()
print(f" Graphs in database: {graphs}\n")

# Clean up
print("7. Cleaning up...")
graph.delete()
print(" ✓ Graph deleted")
print(" ✓ Embedded FalkorDB will shut down when the program exits\n")

print("=== Example Complete ===")


def persistent_example():
"""
Example showing how to persist data across connections.
"""
print("\n=== Persistent Embedded Example ===\n")

import tempfile
import os

# Create a temporary database file
tmpdir = tempfile.mkdtemp()
dbfile = os.path.join(tmpdir, "persistent.db")

print(f"1. Creating persistent database at: {dbfile}")

# First connection - create data
print("2. First connection - creating data...")
db1 = FalkorDB(embedded=True, dbfilename=dbfile)
graph1 = db1.select_graph('persistent_graph')
graph1.query("CREATE (n:Data {value: 'This data persists!'})")
print(" ✓ Data created\n")

# Close the first connection
del graph1
del db1
print("3. First connection closed\n")

# Second connection - retrieve data
print("4. Second connection - retrieving data...")
db2 = FalkorDB(embedded=True, dbfilename=dbfile)
graph2 = db2.select_graph('persistent_graph')
result = graph2.query("MATCH (n:Data) RETURN n.value")
print(f" Retrieved value: {result.result_set[0][0]}")
print(" ✓ Data persisted across connections!\n")

# Clean up
graph2.delete()
del graph2
del db2

# Remove the temporary directory
import shutil
shutil.rmtree(tmpdir)

print("=== Persistent Example Complete ===")


if __name__ == "__main__":
try:
main()
persistent_example()
except ImportError as e:
if "pip install falkordb[embedded]" in str(e):
print("ERROR: Embedded FalkorDB is not installed.")
print("Please run: pip install falkordb[embedded]")
else:
raise
13 changes: 12 additions & 1 deletion falkordb/asyncio/falkordb.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import redis.asyncio as redis
from .cluster import *
from .graph import AsyncGraph
from typing import List, Union
from typing import List, Union, Optional

# config command
LIST_CMD = "GRAPH.LIST"
Expand Down Expand Up @@ -63,7 +63,18 @@ def __init__(
reinitialize_steps=5,
read_from_replicas=False,
address_remap=None,
# Embedded FalkorDB Params
embedded=False,
dbfilename: Optional[str] = None,
serverconfig: Optional[dict] = None,
):
# Embedded mode is not supported for asyncio
if embedded:
raise NotImplementedError(
"Embedded FalkorDB is not supported with asyncio. "
"Please use the synchronous FalkorDB class instead: "
"from falkordb import FalkorDB"
)

conn = redis.Redis(host=host, port=port, db=0, password=password,
socket_timeout=socket_timeout,
Expand Down
10 changes: 10 additions & 0 deletions falkordb/embedded/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright (c) 2024, FalkorDB
# Licensed under the MIT License
"""
This module provides embedded FalkorDB functionality.
It manages a local Redis+FalkorDB process that runs automatically.
"""

__all__ = ['EmbeddedFalkorDB']

from .client import EmbeddedFalkorDB # NOQA
Loading