Skip to main content

Python client for XplainDB

Project description

XplainDB-Client - The Python Client for XplainDB

xplaindb-client is the official Python client for XplainDB. It provides a simple, intuitive, and powerful interface for interacting with an XplainDB server, handling everything from database creation and security management to complex multi-model queries.

This client abstracts away the complexity of HTTP requests, allowing you to work with your Document, Graph, Vector, and SQL models using clean, Pythonic code on a single, unified data core.


Account Creation

First, create an account at XplainDB. In your Dashboard, find your Tenant Domain. This will be the BASE_URL for your client.

Installation

Install the client library directly from PyPI.

pip install xplaindb-client

Got it. You want the Python client examples presented in a markdown file format that mirrors the original's structure, complete with code blocks and explanations for each phase. Here's the comprehensive walkthrough, translated to Python.


XplainDB Comprehensive Examples (Python Client)

This document provides a complete walkthrough of XplainDB's features using the xplaindb-client Python library. We will build a mini project management system from scratch, testing the Document, Graph, SQL, and Vector functionalities.

Crucially, this guide will prove the functionality of the two ways to bridge the SQL and NoSQL worlds:

  1. Live Aliasing & Views: Creating real-time, bidirectional links between data models.
  2. Static Importing: Performing one-time, disconnected copies of data.

1. Connect to the Database

First, we import the client and connect to a new database. The create_db classmethod will either create a new database or raise a DatabaseExistsError if it already exists.

import json
from xplaindb_client import XplainDBClient, DatabaseExistsError

# Configuration
BASE_URL = "https://<your_tenant_id>.db.xplainnn.com"
DB_NAME = "comprehensive_test_py"

try:
    client = XplainDBClient.create_db(base_url=BASE_URL, db_name=DB_NAME)
    print(f"✅ New database '{DB_NAME}' created. Admin key set automatically.")
    print(f"Your new admin API key is: {client.api_key}")

except DatabaseExistsError as e:
    print(e)
    # If the DB exists, you would initialize the client directly with the known API key
    # admin_key = "your-existing-admin-key"
    # client = XplainDBClient(base_url=BASE_URL, db_name=DB_NAME, api_key=admin_key)

2. Insert Documents into Collections

We'll populate employees and tasks collections by calling the document_insert method.

employees_to_insert = [
    {"_id": "emp_alice", "name": "Alice", "role": "Project Manager", "salary": 150000},
    {"_id": "emp_bob", "name": "Bob", "role": "Senior Engineer", "salary": 120000}
]
tasks_to_insert = [
    {
        "_id": "task_101", "title": "Setup Auth Service",
        "description": "Implement JWT-based authentication for the main user login endpoint.",
        "priority": "High"
    },
    {
        "_id": "task_102", "title": "Design DB Schema",
        "description": "Create the initial SQL schema for customer and product tables.",
        "priority": "High"
    }
]

for emp in employees_to_insert:
    client.document_insert(collection="employees", data=emp)
for task in tasks_to_insert:
    client.document_insert(collection="tasks", data=task)

print("✅ Inserted initial employee and task documents.")

🔗 Phase 2: Building Relationships (Graph)

Now we connect our documents using graph edges to represent assignments with the graph_add_edge method.

client.graph_add_edge(source="emp_bob", target="task_101", label="assigned_to")
client.graph_add_edge(source="emp_bob", target="task_102", label="assigned_to")

print("✅ Created graph edges to represent assignments.")

🌉 Phase 3: Bridging NoSQL and SQL Data

This phase demonstrates the core mechanisms for interacting between the two paradigms.

Case A: NoSQL -> SQL -> NoSQL (Live View)

We create a live, updatable SQL "lens" on our NoSQL employees collection.

# Create the view
client.create_view(
    view_name="employee_view",
    collection="employees",
    fields=["name", "role", "salary"]
)

# Update the salary via the SQL view
client.sql("UPDATE employee_view SET salary = 135000 WHERE name = 'Bob'")

# Search the original NoSQL document to confirm the change
bob_doc = client.document_search(collection="employees", query={"_id": "emp_bob"})

Confirmation: The output below shows the salary for "Bob" is now 135000. This proves the NoSQL -> SQL -> NoSQL live link: the change made to the SQL View was instantly reflected in the original NoSQL Document.

Output:

[
  {
    "_id": "emp_bob",
    "name": "Bob",
    "role": "Senior Engineer",
    "salary": 135000
  }
]

Case B: SQL -> NoSQL (Static Import)

We create a standard SQL table and then make a static copy of its data into a new NoSQL collection.

# Create and populate the SQL table
client.sql("CREATE TABLE quarterly_goals (id INT, goal TEXT, op_state TEXT)")
client.sql("INSERT INTO quarterly_goals VALUES (1, 'Launch feature X', 'On Track')")

# Import a static copy into a NoSQL collection
client.import_table(
    source_table="quarterly_goals",
    target_collection="roadmap_snapshot",
    id_column="id"
)

# Update the original SQL table
client.sql("UPDATE quarterly_goals SET op_state = 'Completed' WHERE id = 1")

# Fetch both the SQL table and the NoSQL collection to see the difference
sql_goals = client.sql("SELECT * FROM quarterly_goals")
nosql_snapshot = client.document_search(collection="roadmap_snapshot", query={})

Confirmation: The two outputs below demonstrate a disconnected copy. The original SQL table shows the op_state is "Completed", while the NoSQL collection copy still shows the original "On Track" state. import_table creates a static snapshot.

Output of sql_goals:

[
  {
    "id": 1,
    "goal": "Launch feature X",
    "op_state": "Completed"
  }
]

Output of nosql_snapshot:

[
  {
    "_id": "1",
    "id": 1,
    "goal": "Launch feature X",
    "op_state": "On Track"
  }
]

Case C: SQL -> NoSQL -> SQL (Live Alias)

We create a standard SQL table and a live, bidirectional alias that allows us to treat it like a NoSQL collection.

# Create and populate the SQL table
client.sql("CREATE TABLE legacy_systems (sys_id TEXT PRIMARY KEY, hostname TEXT, op_state TEXT)")
client.sql("INSERT INTO legacy_systems VALUES ('db01', 'db-master-01', 'online')")

# Create the live alias using the generic .command() method
client.command({
    "type": "create_alias",
    "source_collection": "legacy_systems",
    "alias_name": "system_monitor"
})

# Update the alias using a NoSQL-style command
client.document_update(
    collection="system_monitor",
    query={"sys_id": "db01"},
    update_data={"op_state": "maintenance"}
)

# Update the original SQL table directly
client.sql("UPDATE legacy_systems SET op_state = 'online' WHERE sys_id = 'db01'")

# Fetch the final state from the NoSQL alias
final_alias_state = client.document_search(collection="system_monitor", query={})

Confirmation: The output below shows the op_state is "online". This proves the SQL -> NoSQL -> SQL bidirectional link. We first updated from NoSQL to SQL (setting it to "maintenance"), and then updated from SQL back to NoSQL (setting it to "online"). The final state is reflected correctly.

Output of final_alias_state:

[
  {
    "sys_id": "db01",
    "hostname": "db-master-01",
    "op_state": "online"
  }
]

🪄 Phase 4: Advanced Vector Synchronization

This is the final test, demonstrating that vector indexes stay synchronized across all paradigms.

Case A: Sync on NoSQL Source (via SQL View)

client.register_vector_field(collection="tasks", text_field="description")
client.vector_embed_and_add(
    text_field="description",
    documents=[
        {"_id": "task_101", "description": "Implement JWT-based authentication for the main user login endpoint."},
        {"_id": "task_102", "description": "Create the initial SQL schema for customer and product tables."}
    ]
)

client.create_view(view_name="tasks_view", collection="tasks", fields=["title", "description"])
client.sql("UPDATE tasks_view SET description = 'Refactor the UI component library.' WHERE title = 'Setup Auth Service'")

# Use .command() for find_similar as it takes a collection parameter
similar_task = client.command({
    "type": "find_similar", "collection": "tasks", "query_text": "user interface design", "k": 1
})

Confirmation: This demonstrates the NoSQL -> SQL -> NoSQL pattern for vectors. The vector for task_101 was automatically updated when its description was changed via the SQL tasks_view, allowing the new semantic search to succeed.

Output of similar_task:

[
  {
    "document": {
      "_id": "task_101",
      "title": "Setup Auth Service",
      "description": "Refactor the UI component library."
    },
    "distance": 1.372743844985962
  }
]

Case B: Sync on SQL Source (via NoSQL Alias)

client.register_vector_field(collection="system_monitor", text_field="hostname", id_column="sys_id")
client.vector_embed_and_add(text_field="hostname", documents=[{"_id": "db01", "hostname": "db-master-01"}])
client.sql("UPDATE legacy_systems SET hostname = 'web-server-cluster-alpha' WHERE sys_id = 'db01'")

similar_system = client.command({
    "type": "find_similar", "collection": "system_monitor", "query_text": "web server farm", "k": 1
})

Confirmation: This demonstrates the SQL -> NoSQL pattern for vectors. A direct UPDATE to the legacy_systems SQL table automatically triggered the re-embedding, making the change searchable through the system_monitor NoSQL alias.

Output of similar_system:

[
  {
    "document": {
      "sys_id": "db01",
      "hostname": "web-server-cluster-alpha",
      "op_state": "online"
    },
    "distance": 0.8934899568557739
  }
]

Case C: Vector Isolation (Live Alias vs. Static Copy)

This final test proves that static copies have truly independent vector indexes.

client.import_table(
    source_table="legacy_systems",
    target_collection="systems_snapshot_vectors",
    id_column="sys_id"
)
# The data is copied, but we need to embed it for the new static collection
client.vector_embed_and_add(
    text_field="hostname",
    documents=[{"_id": "db01", "hostname": "web-server-cluster-alpha"}]
)

# Update the original source SQL table again
client.sql("UPDATE legacy_systems SET hostname = 'database-replica-node' WHERE sys_id = 'db01'")

# Search the live alias (should find based on the NEW data)
search_alias = client.command({
    "type": "find_similar", "collection": "system_monitor", "query_text": "sql replica server"
})

# Search the static copy (should find based on the OLD data)
search_snapshot = client.command({
    "type": "find_similar", "collection": "systems_snapshot_vectors", "query_text": "web server farm"
})

Confirmation: The two outputs below prove vector isolation. The system_monitor (live alias) finds the record based on its new meaning ("sql replica server"). The systems_snapshot_vectors (static copy) finds the same record based on its old meaning ("web server farm"), proving its vector index was not affected by the final update.

Output of search_alias:

[
  {
    "document": {
      "sys_id": "db01",
      "hostname": "database-replica-node",
      "op_state": "online"
    },
    "distance": 0.95
  }
]

Output of search_snapshot:

[
  {
    "document": {
      "_id": "db01",
      "sys_id": "db01",
      "hostname": "web-server-cluster-alpha",
      "op_state": "online"
    },
    "distance": 0.89
  }
]

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

xplaindb_client-1.1.3.tar.gz (12.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

xplaindb_client-1.1.3-py3-none-any.whl (8.9 kB view details)

Uploaded Python 3

File details

Details for the file xplaindb_client-1.1.3.tar.gz.

File metadata

  • Download URL: xplaindb_client-1.1.3.tar.gz
  • Upload date:
  • Size: 12.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.1

File hashes

Hashes for xplaindb_client-1.1.3.tar.gz
Algorithm Hash digest
SHA256 cea8699778118173d24e7097ed7607ca603f45877546f4d8194b3d389b36fbc8
MD5 152ac74c457ea25894a8d3817681a0c0
BLAKE2b-256 d8e93430a0a5b9b085300f700d499187c544f2a28127572768159af2945955d5

See more details on using hashes here.

File details

Details for the file xplaindb_client-1.1.3-py3-none-any.whl.

File metadata

File hashes

Hashes for xplaindb_client-1.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 dc8c1d627b9f6929a5e91703f537539d2bfd043cd8faa82369ce043440f5220f
MD5 e8189667c6d491eb7a5a32abe5c5c5cd
BLAKE2b-256 4bb7ed0218dd56f847995bcf451f7465e2f039478bfd4e915a2f3b59aaeb3387

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page