diff --git a/README.md b/README.md
index 39a5285..66ef82c 100644
--- a/README.md
+++ b/README.md
@@ -3,219 +3,123 @@

# RushDB Python SDK
-
+

-

RushDB is an instant database for modern apps and DS/ML ops built on top of Neo4j.
+It automates data normalization, manages relationships, and infers data types.
-It automates data normalization, manages relationships, and infers data types, enabling developers to focus on building features rather than wrestling with data.
+[📖 Documentation](https://docs.rushdb.com/python-sdk/introduction) • [🌐 Website](https://rushdb.com) • [☁️ Cloud Platform](https://app.rushdb.com)
-[🌐 Homepage](https://rushdb.com) — [📢 Blog](https://rushdb.com/blog) — [☁️ Platform ](https://app.rushdb.com) — [📚 Docs](https://docs.rushdb.com/python-sdk/records-api) — [🧑💻 Examples](https://github.com/rush-db/examples)
----
-
## Installation
-Install the RushDB Python SDK via pip:
-
-
```sh
pip install rushdb
```
----
-
-## Usage
-
-### **1. Setup SDK**
+## Quick Start
```python
from rushdb import RushDB
-db = RushDB("API_TOKEN", base_url="https://api.rushdb.com")
-```
+# Initialize the client
+db = RushDB("YOUR_API_TOKEN")
----
+# Create a record
+user = db.records.create(
+ label="USER",
+ data={
+ "name": "John Doe",
+ "email": "john@example.com",
+ "age": 30
+ }
+)
-### **2. Push any JSON data**
+# Find records
+results = db.records.find({
+ "where": {
+ "age": {"$gte": 18},
+ "name": {"$startsWith": "J"}
+ },
+ "limit": 10
+})
+# Create relationships
+company = db.records.create(
+ label="COMPANY",
+ data={"name": "Acme Inc."}
+)
+
+# Attach records with a relationship
+user.attach(
+ target=company,
+ options={"type": "WORKS_AT", "direction": "out"}
+)
+```
+
+## Pushing Nested JSON
+
+RushDB automatically normalizes nested objects into a graph structure:
```python
-company_data = {
+# Push nested JSON with automatic relationship creation
+db.records.create_many("COMPANY", {
"name": "Google LLC",
- "address": "1600 Amphitheatre Parkway, Mountain View, CA 94043, USA",
- "foundedAt": "1998-09-04T00:00:00.000Z",
"rating": 4.9,
"DEPARTMENT": [{
"name": "Research & Development",
- "description": "Innovating and creating advanced technologies for AI, cloud computing, and consumer devices.",
"PROJECT": [{
"name": "Bard AI",
- "description": "A state-of-the-art generative AI model for natural language understanding and creation.",
- "active": True,
- "budget": 1200000000,
"EMPLOYEE": [{
"name": "Jeff Dean",
- "position": "Head of AI Research",
- "email": "jeff@google.com",
- "dob": "1968-07-16T00:00:00.000Z",
- "salary": 3000000
+ "position": "Head of AI Research"
}]
}]
}]
-}
-
-db.records.create_many("COMPANY", company_data)
+})
```
-This operation will create 4 Records with proper data types and relationships according to this structure:
+## Complete Documentation
-```cypher
-(Record:COMPANY)
- -[r0:RUSHDB_DEFAULT_RELATION]->
- (Record:DEPARTMENT)
- -[r1:RUSHDB_DEFAULT_RELATION]->
- (Record:PROJECT)
- -[r2:RUSHDB_DEFAULT_RELATION]->
- (Record:EMPLOYEE)
-```
+For comprehensive documentation, tutorials, and examples, please visit:
----
+**[docs.rushdb.com/python-sdk](https://docs.rushdb.com/python-sdk/introduction)**
-### **3. Find Records by specific criteria**
+Documentation includes:
-```python
-query = {
- "labels": ["EMPLOYEE"],
- "where": {
- "position": {"$contains": "AI"},
- "PROJECT": {
- "DEPARTMENT": {
- "COMPANY": {
- "rating": {"$gte": 4}
- }
- }
- }
- }
-}
+- Complete Records API reference
+- Relationship management
+- Complex query examples
+- Transaction usage
+- Vector search capabilities
+- Data import tools
-matched_employees = db.records.find(query)
+## Support
-company = db.records.find_uniq("COMPANY", {"where": {"name": "Google LLC"}})
-```
+- [GitHub Issues](https://github.com/rush-db/rushdb-python/issues) - Bug reports and feature requests
+- [Discord Community](https://discord.gg/rushdb) - Get help from the community
+- [Email Support](mailto:support@rushdb.com) - Direct support from the RushDB team
---
-
-# Documentation
-
-# RecordsAPI Documentation
-
-The `RecordsAPI` class provides methods for managing records in RushDB. It handles record creation, updates, deletion, searching, and relationship management.
-
-## Methods
-
-### create()
-
-Creates a new record in RushDB.
-
-**Signature:**
-```python
-def create(
- self,
- label: str,
- data: Dict[str, Any],
- options: Optional[Dict[str, bool]] = None,
- transaction: Optional[Transaction] = None
-) -> Record
-```
-
-**Arguments:**
-- `label` (str): Label for the record
-- `data` (Dict[str, Any]): Record data
-- `options` (Optional[Dict[str, bool]]): Optional parsing and response options
- - `returnResult` (bool): Whether to return the created record
- - `suggestTypes` (bool): Whether to suggest property types
-- `transaction` (Optional[Transaction]): Optional transaction object
-
-**Returns:**
-- `Record`: Created record object
-
-**Example:**
-```python
-# Create a new company record
-data = {
- "name": "Google LLC",
- "address": "1600 Amphitheatre Parkway",
- "foundedAt": "1998-09-04T00:00:00.000Z",
- "rating": 4.9
-}
-
-record = db.records.create(
- label="COMPANY",
- data=data,
- options={"returnResult": True, "suggestTypes": True}
-)
-```
-
-### create_many()
-
-Creates multiple records in a single operation.
-
-**Signature:**
-```python
-def create_many(
- self,
- label: str,
- data: Union[Dict[str, Any], List[Dict[str, Any]]],
- options: Optional[Dict[str, bool]] = None,
- transaction: Optional[Transaction] = None
-) -> List[Record]
-```
-
-**Arguments:**
-- `label` (str): Label for all records
-- `data` (Union[Dict[str, Any], List[Dict[str, Any]]]): List or Dict of record data
-- `options` (Optional[Dict[str, bool]]): Optional parsing and response options
-- `transaction` (Optional[Transaction]): Optional transaction object
-
-**Returns:**
-- `List[Record]`: List of created record objects
-
-**Example:**
-```python
-# Create multiple company records
-data = [
- {
- "name": "Apple Inc",
- "address": "One Apple Park Way",
- "foundedAt": "1976-04-01T00:00:00.000Z",
- "rating": 4.8
- },
- {
- "name": "Microsoft Corporation",
- "address": "One Microsoft Way",
- "foundedAt": "1975-04-04T00:00:00.000Z",
- "rating": 4.7
- }
-]
-
-records = db.records.create_many(
- label="COMPANY",
- data=data,
- options={"returnResult": True, "suggestTypes": True}
-)
-```
+
### set()
Updates a record by ID, replacing all data.
**Signature:**
+
```python
def set(
self,
@@ -226,14 +130,17 @@ def set(
```
**Arguments:**
+
- `record_id` (str): ID of the record to update
- `data` (Dict[str, Any]): New record data
- `transaction` (Optional[Transaction]): Optional transaction object
**Returns:**
+
- `Dict[str, str]`: Response data
**Example:**
+
```python
# Update entire record data
new_data = {
@@ -252,6 +159,7 @@ response = db.records.set(
Updates specific fields of a record by ID.
**Signature:**
+
```python
def update(
self,
@@ -262,14 +170,17 @@ def update(
```
**Arguments:**
+
- `record_id` (str): ID of the record to update
- `data` (Dict[str, Any]): Partial record data to update
- `transaction` (Optional[Transaction]): Optional transaction object
**Returns:**
+
- `Dict[str, str]`: Response data
**Example:**
+
```python
# Update specific fields
updates = {
@@ -288,6 +199,7 @@ response = db.records.update(
Searches for records matching specified criteria.
**Signature:**
+
```python
def find(
self,
@@ -298,14 +210,17 @@ def find(
```
**Arguments:**
+
- `query` (Optional[SearchQuery]): Search query parameters
- `record_id` (Optional[str]): Optional record ID to search from
- `transaction` (Optional[Transaction]): Optional transaction object
**Returns:**
+
- `List[Record]`: List of matching records
**Example:**
+
```python
# Search for records with complex criteria
query = {
@@ -328,6 +243,7 @@ records = db.records.find(query=query)
Deletes records matching a query.
**Signature:**
+
```python
def delete(
self,
@@ -337,13 +253,16 @@ def delete(
```
**Arguments:**
+
- `query` (SearchQuery): Query to match records for deletion
- `transaction` (Optional[Transaction]): Optional transaction object
**Returns:**
+
- `Dict[str, str]`: Response data
**Example:**
+
```python
# Delete records matching criteria
query = {
@@ -361,6 +280,7 @@ response = db.records.delete(query)
Deletes one or more records by ID.
**Signature:**
+
```python
def delete_by_id(
self,
@@ -370,13 +290,16 @@ def delete_by_id(
```
**Arguments:**
+
- `id_or_ids` (Union[str, List[str]]): Single ID or list of IDs to delete
- `transaction` (Optional[Transaction]): Optional transaction object
**Returns:**
+
- `Dict[str, str]`: Response data
**Example:**
+
```python
# Delete single record
response = db.records.delete_by_id("record-123")
@@ -394,6 +317,7 @@ response = db.records.delete_by_id([
Creates relationships between records.
**Signature:**
+
```python
def attach(
self,
@@ -405,6 +329,7 @@ def attach(
```
**Arguments:**
+
- `source` (Union[str, Dict[str, Any]]): Source record ID or data
- `target` (Union[str, List[str], Dict[str, Any], List[Dict[str, Any]], Record, List[Record]]): Target record(s)
- `options` (Optional[RelationshipOptions]): Relationship options
@@ -413,9 +338,11 @@ def attach(
- `transaction` (Optional[Transaction]): Optional transaction object
**Returns:**
+
- `Dict[str, str]`: Response data
**Example:**
+
```python
# Create relationship between records
options = RelationshipOptions(
@@ -435,6 +362,7 @@ response = db.records.attach(
Removes relationships between records.
**Signature:**
+
```python
def detach(
self,
@@ -446,6 +374,7 @@ def detach(
```
**Arguments:**
+
- `source` (Union[str, Dict[str, Any]]): Source record ID or data
- `target` (Union[str, List[str], Dict[str, Any], List[Dict[str, Any]], Record, List[Record]]): Target record(s)
- `options` (Optional[RelationshipDetachOptions]): Detach options
@@ -454,9 +383,11 @@ def detach(
- `transaction` (Optional[Transaction]): Optional transaction object
**Returns:**
+
- `Dict[str, str]`: Response data
**Example:**
+
```python
# Remove relationships between records
options = RelationshipDetachOptions(
@@ -476,6 +407,7 @@ response = db.records.detach(
Imports records from CSV data.
**Signature:**
+
```python
def import_csv(
self,
@@ -487,15 +419,18 @@ def import_csv(
```
**Arguments:**
+
- `label` (str): Label for imported records
- `csv_data` (Union[str, bytes]): CSV data to import
- `options` (Optional[Dict[str, bool]]): Import options
- `transaction` (Optional[Transaction]): Optional transaction object
**Returns:**
+
- `List[Dict[str, Any]]`: Imported records data
**Example:**
+
```python
# Import records from CSV
csv_data = """name,age,department,role
@@ -532,6 +467,7 @@ Gets the record's unique identifier.
**Type:** `str`
**Example:**
+
```python
record = db.records.create("USER", {"name": "John"})
print(record.id) # e.g., "1234abcd-5678-..."
@@ -544,6 +480,7 @@ Gets the record's property types.
**Type:** `str`
**Example:**
+
```python
record = db.records.create("USER", {"name": "John", "age": 25})
print(record.proptypes) # Returns property type definitions
@@ -556,6 +493,7 @@ Gets the record's label.
**Type:** `str`
**Example:**
+
```python
record = db.records.create("USER", {"name": "John"})
print(record.label) # "USER"
@@ -568,6 +506,7 @@ Gets the record's creation timestamp from its ID.
**Type:** `int`
**Example:**
+
```python
record = db.records.create("USER", {"name": "John"})
print(record.timestamp) # Unix timestamp in milliseconds
@@ -580,6 +519,7 @@ Gets the record's creation date.
**Type:** `datetime`
**Example:**
+
```python
record = db.records.create("USER", {"name": "John"})
print(record.date) # datetime object
@@ -592,6 +532,7 @@ print(record.date) # datetime object
Updates all data for the record.
**Signature:**
+
```python
def set(
self,
@@ -601,13 +542,16 @@ def set(
```
**Arguments:**
+
- `data` (Dict[str, Any]): New record data
- `transaction` (Optional[Transaction]): Optional transaction object
**Returns:**
+
- `Dict[str, str]`: Response data
**Example:**
+
```python
record = db.records.create("USER", {"name": "John"})
response = record.set({
@@ -622,6 +566,7 @@ response = record.set({
Updates specific fields of the record.
**Signature:**
+
```python
def update(
self,
@@ -631,13 +576,16 @@ def update(
```
**Arguments:**
+
- `data` (Dict[str, Any]): Partial record data to update
- `transaction` (Optional[Transaction]): Optional transaction object
**Returns:**
+
- `Dict[str, str]`: Response data
**Example:**
+
```python
record = db.records.create("USER", {
"name": "John",
@@ -653,6 +601,7 @@ response = record.update({
Creates relationships with other records.
**Signature:**
+
```python
def attach(
self,
@@ -663,6 +612,7 @@ def attach(
```
**Arguments:**
+
- `target` (Union[str, List[str], Dict[str, Any], List[Dict[str, Any]], Record, List[Record]]): Target record(s)
- `options` (Optional[RelationshipOptions]): Relationship options
- `direction` (Optional[Literal["in", "out"]]): Relationship direction
@@ -670,9 +620,11 @@ def attach(
- `transaction` (Optional[Transaction]): Optional transaction object
**Returns:**
+
- `Dict[str, str]`: Response data
**Example:**
+
```python
# Create two records
user = db.records.create("USER", {"name": "John"})
@@ -693,6 +645,7 @@ response = user.attach(
Removes relationships with other records.
**Signature:**
+
```python
def detach(
self,
@@ -703,6 +656,7 @@ def detach(
```
**Arguments:**
+
- `target` (Union[str, List[str], Dict[str, Any], List[Dict[str, Any]], Record, List[Record]]): Target record(s)
- `options` (Optional[RelationshipDetachOptions]): Detach options
- `direction` (Optional[Literal["in", "out"]]): Relationship direction
@@ -710,9 +664,11 @@ def detach(
- `transaction` (Optional[Transaction]): Optional transaction object
**Returns:**
+
- `Dict[str, str]`: Response data
**Example:**
+
```python
# Detach user from group
response = user.detach(
@@ -729,6 +685,7 @@ response = user.detach(
Deletes the record.
**Signature:**
+
```python
def delete(
self,
@@ -737,12 +694,15 @@ def delete(
```
**Arguments:**
+
- `transaction` (Optional[Transaction]): Optional transaction object
**Returns:**
+
- `Dict[str, str]`: Response data
**Example:**
+
```python
user = db.records.create("USER", {"name": "John"})
response = user.delete()
@@ -823,26 +783,26 @@ with db.transactions.begin() as transaction:
{"name": "John Doe"},
transaction=transaction
)
-
+
# Update user
user.update(
{"status": "active"},
transaction=transaction
)
-
+
# Create and attach department
dept = db.records.create(
"DEPARTMENT",
{"name": "Engineering"},
transaction=transaction
)
-
+
user.attach(
target=dept,
options=RelationshipOptions(type="BELONGS_TO"),
transaction=transaction
)
-
+
# Transaction will automatically commit if no errors occur
# If an error occurs, it will automatically rollback
```
@@ -866,6 +826,7 @@ class PropertiesAPI(BaseAPI):
Retrieves a list of properties based on optional search criteria.
**Signature:**
+
```python
def find(
self,
@@ -875,16 +836,19 @@ def find(
```
**Arguments:**
+
- `query` (Optional[SearchQuery]): Search query parameters for filtering properties
- `transaction` (Optional[Transaction]): Optional transaction object
**Returns:**
+
- `List[Property]`: List of properties matching the search criteria
**Example:**
+
```python
# Find all properties
-properties = client.properties.find()
+properties = db.properties.find()
# Find properties with specific criteria
query = {
@@ -894,7 +858,7 @@ query = {
},
"limit": 10 # Limit to 10 results
}
-filtered_properties = client.properties.find(query)
+filtered_properties = db.properties.find(query)
```
### find_by_id()
@@ -902,6 +866,7 @@ filtered_properties = client.properties.find(query)
Retrieves a specific property by its ID.
**Signature:**
+
```python
def find_by_id(
self,
@@ -911,16 +876,19 @@ def find_by_id(
```
**Arguments:**
+
- `property_id` (str): Unique identifier of the property
- `transaction` (Optional[Transaction]): Optional transaction object
**Returns:**
+
- `Property`: Property details
**Example:**
+
```python
# Retrieve a specific property by ID
-property_details = client.properties.find_by_id("prop_123456")
+property_details = db.properties.find_by_id("prop_123456")
```
### delete()
@@ -928,6 +896,7 @@ property_details = client.properties.find_by_id("prop_123456")
Deletes a property by its ID.
**Signature:**
+
```python
def delete(
self,
@@ -937,16 +906,19 @@ def delete(
```
**Arguments:**
+
- `property_id` (str): Unique identifier of the property to delete
- `transaction` (Optional[Transaction]): Optional transaction object
**Returns:**
+
- `None`
**Example:**
+
```python
# Delete a property
-client.properties.delete("prop_123456")
+db.properties.delete("prop_123456")
```
### values()
@@ -954,6 +926,7 @@ client.properties.delete("prop_123456")
Retrieves values for a specific property with optional sorting and pagination.
**Signature:**
+
```python
def values(
self,
@@ -966,6 +939,7 @@ def values(
```
**Arguments:**
+
- `property_id` (str): Unique identifier of the property
- `sort` (Optional[Literal["asc", "desc"]]): Sort order of values
- `skip` (Optional[int]): Number of values to skip (for pagination)
@@ -973,12 +947,14 @@ def values(
- `transaction` (Optional[Transaction]): Optional transaction object
**Returns:**
+
- `PropertyValuesData`: Property values data, including optional min/max and list of values
**Example:**
+
```python
# Get property values
-values_data = client.properties.values(
+values_data = db.properties.values(
property_id="prop_age",
sort="desc", # Sort values in descending order
skip=0, # Start from the first value
@@ -995,7 +971,7 @@ print(values_data.get('max')) # Maximum value (for numeric properties)
```python
# Find all properties
-all_properties = client.properties.find()
+all_properties = db.properties.find()
for prop in all_properties:
print(f"Property ID: {prop['id']}")
print(f"Name: {prop['name']}")
@@ -1011,12 +987,12 @@ query = {
},
"limit": 5 # Limit to 5 results
}
-numeric_score_properties = client.properties.find(query)
+numeric_score_properties = db.properties.find(query)
# Get values for a specific property
if numeric_score_properties:
first_prop = numeric_score_properties[0]
- prop_values = client.properties.values(
+ prop_values = db.properties.values(
property_id=first_prop['id'],
sort="desc",
limit=50
@@ -1024,15 +1000,16 @@ if numeric_score_properties:
print(f"Values for {first_prop['name']}:")
print(f"Min: {prop_values.get('min')}")
print(f"Max: {prop_values.get('max')}")
-
+
# Detailed property examination
- detailed_prop = client.properties.find_by_id(first_prop['id'])
+ detailed_prop = db.properties.find_by_id(first_prop['id'])
print("Detailed Property Info:", detailed_prop)
```
## Property Types and Structures
RushDB supports the following property types:
+
- `"boolean"`: True/False values
- `"datetime"`: Date and time values
- `"null"`: Null/empty values
@@ -1040,6 +1017,7 @@ RushDB supports the following property types:
- `"string"`: Text values
### Property Structure Example
+
```python
property = {
"id": "prop_unique_id",
@@ -1062,14 +1040,14 @@ Properties API methods support optional transactions for atomic operations:
```python
# Using a transaction
-with client.transactions.begin() as transaction:
+with db.transactions.begin() as transaction:
# Perform multiple property-related operations
- property_to_delete = client.properties.find(
+ property_to_delete = db.properties.find(
{"where": {"name": "temp_property"}},
transaction=transaction
)[0]
-
- client.properties.delete(
+
+ db.properties.delete(
property_id=property_to_delete['id'],
transaction=transaction
)
@@ -1083,7 +1061,7 @@ When working with the PropertiesAPI, be prepared to handle potential errors:
```python
try:
# Attempt to find or delete a property
- property_details = client.properties.find_by_id("non_existent_prop")
+ property_details = db.properties.find_by_id("non_existent_prop")
except RushDBError as e:
print(f"Error: {e}")
print(f"Error Details: {e.details}")
diff --git a/pyproject.toml b/pyproject.toml
index 9697eff..eec6fe6 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "rushdb"
-version = "0.3.0"
+version = "1.0.0"
description = "RushDB Python SDK"
authors = ["RushDB Team "]
license = "Apache-2.0"
diff --git a/src/rushdb/api/labels.py b/src/rushdb/api/labels.py
index 4710a61..cf3cd31 100644
--- a/src/rushdb/api/labels.py
+++ b/src/rushdb/api/labels.py
@@ -19,7 +19,7 @@ def list(
return self.client._make_request(
"POST",
- "/api/v1/labels",
+ "/api/v1/labels/search",
data=typing.cast(typing.Dict[str, typing.Any], query or {}),
headers=headers,
)
diff --git a/src/rushdb/api/properties.py b/src/rushdb/api/properties.py
index 0f276cb..70dd99e 100644
--- a/src/rushdb/api/properties.py
+++ b/src/rushdb/api/properties.py
@@ -20,7 +20,7 @@ def find(
return self.client._make_request(
"POST",
- "/api/v1/properties",
+ "/api/v1/properties/search",
typing.cast(typing.Dict[str, typing.Any], query or {}),
headers,
)
diff --git a/src/rushdb/api/records.py b/src/rushdb/api/records.py
index 5ba5c4d..528b908 100644
--- a/src/rushdb/api/records.py
+++ b/src/rushdb/api/records.py
@@ -59,7 +59,7 @@ def create(
payload = {
"label": label,
- "payload": data,
+ "data": data,
"options": options or {"returnResult": True, "suggestTypes": True},
}
response = self.client._make_request(
@@ -89,7 +89,7 @@ def create_many(
payload = {
"label": label,
- "payload": data,
+ "data": data,
"options": options or {"returnResult": True, "suggestTypes": True},
}
response = self.client._make_request(
@@ -120,7 +120,7 @@ def attach(
if options:
payload.update(typing.cast(typing.Dict[str, typing.Any], options))
return self.client._make_request(
- "POST", f"/api/v1/records/{source_id}/relations", payload, headers
+ "POST", f"/api/v1/relationships/{source_id}", payload, headers
)
def detach(
@@ -146,7 +146,7 @@ def detach(
if options:
payload.update(typing.cast(typing.Dict[str, typing.Any], options))
return self.client._make_request(
- "PUT", f"/api/v1/records/{source_id}/relations", payload, headers
+ "PUT", f"/api/v1/relationships/{source_id}", payload, headers
)
def delete(
@@ -219,7 +219,7 @@ def import_csv(
payload = {
"label": label,
- "payload": csv_data,
+ "data": csv_data,
"options": options or {"returnResult": True, "suggestTypes": True},
}
diff --git a/src/rushdb/api/relationships.py b/src/rushdb/api/relationships.py
index 712a9cc..4b2328c 100644
--- a/src/rushdb/api/relationships.py
+++ b/src/rushdb/api/relationships.py
@@ -44,7 +44,7 @@ async def find(
# Construct path with query string
query_string = f"?{urlencode(query_params)}" if query_params else ""
- path = f"/records/relations/search{query_string}"
+ path = f"/relationships/search{query_string}"
# Build headers with transaction if present
headers = Transaction._build_transaction_header(transaction)