Skip to content

Commit b1d4115

Browse files
committed
Split client into separate files
1 parent a62431e commit b1d4115

17 files changed

+555
-499
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pip install rushdb
1111
## Quick Start
1212

1313
```python
14-
from rushdb import RushDBClient
14+
from src.rushdb import RushDBClient
1515

1616
# Initialize the client
1717
client = RushDBClient("http://localhost:8000", "your-api-key")

rushdb/__init__.py

Lines changed: 0 additions & 9 deletions
This file was deleted.

rushdb/client/__init__.py

Lines changed: 0 additions & 8 deletions
This file was deleted.

rushdb/client/client.py

Lines changed: 0 additions & 479 deletions
This file was deleted.

src/__init__.py

Whitespace-only changes.

src/rushdb/__init__.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
"""RushDB Client Package
2+
3+
Exposes the RushDBClient class.
4+
"""
5+
6+
from .client import RushDBClient
7+
from .common import RushDBError, RelationOptions, RelationDetachOptions
8+
from .record import Record
9+
from .transaction import Transaction
10+
from .property import Property
11+
12+
__all__ = ['RushDBClient', 'RushDBError', 'Record', 'RelationOptions', 'RelationDetachOptions', 'Transaction', 'Property']

src/rushdb/client.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
"""RushDB Client"""
2+
3+
import json
4+
import urllib.request
5+
import urllib.parse
6+
import urllib.error
7+
from typing import Any, Dict, Optional
8+
9+
from src.rushdb.common import RushDBError
10+
from src.rushdb.labels_api import LabelsAPI
11+
from src.rushdb.properties_api import PropertiesAPI
12+
from src.rushdb.records_api import RecordsAPI
13+
from src.rushdb.transactions_api import TransactionsAPI
14+
15+
class RushDBClient:
16+
"""Main client for interacting with RushDB."""
17+
DEFAULT_BASE_URL = "https://api.rushdb.com"
18+
19+
def __init__(self, api_key: str, base_url: Optional[str] = None):
20+
"""Initialize the RushDB client.
21+
22+
Args:
23+
api_key: The API key for authentication
24+
base_url: Optional base URL for the RushDB server (default: https://api.rushdb.com)
25+
"""
26+
self.base_url = (base_url or self.DEFAULT_BASE_URL).rstrip('/')
27+
self.api_key = api_key
28+
self.records = RecordsAPI(self)
29+
self.properties = PropertiesAPI(self)
30+
self.labels = LabelsAPI(self)
31+
self.transactions = TransactionsAPI(self)
32+
33+
def _make_request(self, method: str, path: str, data: Optional[Dict] = None, headers: Optional[Dict[str, str]] = None, params: Optional[Dict[str, Any]] = None) -> Any:
34+
"""Make an HTTP request to the RushDB server.
35+
36+
Args:
37+
method: HTTP method (GET, POST, PUT, DELETE)
38+
path: API endpoint path
39+
data: Request body data
40+
headers: Optional request headers
41+
params: Optional URL query parameters
42+
43+
Returns:
44+
The parsed JSON response
45+
"""
46+
# Ensure path starts with /
47+
if not path.startswith('/'):
48+
path = '/' + path
49+
50+
# Clean and encode path components
51+
path = path.strip()
52+
path_parts = [urllib.parse.quote(part, safe='') for part in path.split('/') if part]
53+
clean_path = '/' + '/'.join(path_parts)
54+
55+
# Build URL with query parameters
56+
url = f"{self.base_url}{clean_path}"
57+
if params:
58+
query_string = urllib.parse.urlencode(params)
59+
url = f"{url}?{query_string}"
60+
61+
# Prepare headers
62+
request_headers = {
63+
'token': self.api_key,
64+
'Content-Type': 'application/json',
65+
**(headers or {})
66+
}
67+
68+
try:
69+
# Prepare request body
70+
body = None
71+
if data is not None:
72+
body = json.dumps(data).encode('utf-8')
73+
74+
# Create and send request
75+
request = urllib.request.Request(
76+
url,
77+
data=body,
78+
headers=request_headers,
79+
method=method
80+
)
81+
82+
with urllib.request.urlopen(request) as response:
83+
return json.loads(response.read().decode('utf-8'))
84+
except urllib.error.HTTPError as e:
85+
error_body = json.loads(e.read().decode('utf-8'))
86+
raise RushDBError(error_body.get('message', str(e)), error_body)
87+
except urllib.error.URLError as e:
88+
raise RushDBError(f"Connection error: {str(e)}")
89+
except json.JSONDecodeError as e:
90+
raise RushDBError(f"Invalid JSON response: {str(e)}")
91+
92+
def ping(self) -> bool:
93+
"""Check if the server is reachable."""
94+
try:
95+
self._make_request('GET', '/')
96+
return True
97+
except RushDBError:
98+
return False

src/rushdb/common.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from typing import Dict, List, Optional, Union, TypedDict, Literal
2+
3+
# Relation types
4+
RelationDirection = Literal['in', 'out']
5+
6+
class RelationOptions(TypedDict, total=False):
7+
"""Options for creating relations."""
8+
direction: Optional[RelationDirection]
9+
type: Optional[str]
10+
11+
class RelationDetachOptions(TypedDict, total=False):
12+
"""Options for detaching relations."""
13+
direction: Optional[RelationDirection]
14+
typeOrTypes: Optional[Union[str, List[str]]]
15+
16+
class RushDBError(Exception):
17+
"""Custom exception for RushDB client errors."""
18+
def __init__(self, message: str, details: Optional[Dict] = None):
19+
super().__init__(message)
20+
self.details = details or {}

src/rushdb/labels_api.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from typing import List
2+
3+
from src.rushdb import RushDBClient
4+
5+
6+
class LabelsAPI:
7+
"""API for managing labels in RushDB."""
8+
def __init__(self, client: 'RushDBClient'):
9+
self.client = client
10+
11+
def list(self) -> List[str]:
12+
"""List all labels."""
13+
return self.client._make_request('GET', '/api/v1/labels')
14+
15+
def create(self, label: str) -> None:
16+
"""Create a new label."""
17+
return self.client._make_request('POST', '/api/v1/labels', {'name': label})
18+
19+
def delete(self, label: str) -> None:
20+
"""Delete a label."""
21+
return self.client._make_request('DELETE', f'/api/v1/labels/{label}')

src/rushdb/properties_api.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from typing import List, Dict, Any, Optional
2+
3+
from src.rushdb import RushDBClient
4+
from src.rushdb.property import Property, PropertyValuesData
5+
from src.rushdb.transaction import Transaction
6+
7+
8+
class PropertiesAPI:
9+
"""API for managing properties in RushDB."""
10+
def __init__(self, client: 'RushDBClient'):
11+
self.client = client
12+
13+
def list(self, transaction: Optional[Transaction] = None) -> List[Property]:
14+
"""List all properties."""
15+
headers = Transaction._build_transaction_header(transaction.id if transaction else None)
16+
17+
return self.client._make_request('GET', '/api/v1/properties', headers=headers)
18+
19+
def create(self, data: Dict[str, Any], transaction: Optional[Transaction] = None) -> Property:
20+
"""Create a new property."""
21+
headers = Transaction._build_transaction_header(transaction.id if transaction else None)
22+
23+
return self.client._make_request('POST', '/api/v1/properties', data, headers)
24+
25+
def get(self, property_id: str, transaction: Optional[Transaction] = None) -> Property:
26+
"""Get a property by ID."""
27+
headers = Transaction._build_transaction_header(transaction.id if transaction else None)
28+
29+
return self.client._make_request('GET', f'/api/v1/properties/{property_id}', headers=headers)
30+
31+
def update(self, property_id: str, data: Dict[str, Any], transaction: Optional[Transaction] = None) -> Property:
32+
"""Update a property."""
33+
headers = Transaction._build_transaction_header(transaction.id if transaction else None)
34+
35+
return self.client._make_request('PUT', f'/api/v1/properties/{property_id}', data, headers)
36+
37+
def delete(self, property_id: str, transaction: Optional[Transaction] = None) -> None:
38+
"""Delete a property."""
39+
headers = Transaction._build_transaction_header(transaction.id if transaction else None)
40+
41+
return self.client._make_request('DELETE', f'/api/v1/properties/{property_id}', headers=headers)
42+
43+
def get_values(self, property_id: str, transaction: Optional[Transaction] = None) -> PropertyValuesData:
44+
"""Get values data for a property."""
45+
headers = Transaction._build_transaction_header(transaction.id if transaction else None)
46+
47+
return self.client._make_request('GET', f'/api/v1/properties/{property_id}/values', headers=headers)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy