diff --git a/.changeset/old-hounds-flash.md b/.changeset/old-hounds-flash.md
new file mode 100644
index 0000000..8951278
--- /dev/null
+++ b/.changeset/old-hounds-flash.md
@@ -0,0 +1,9 @@
+---
+'@rushdb/javascript-sdk': minor
+'rushdb-dashboard': minor
+'rushdb-core': minor
+'rushdb-website': minor
+'rushdb-docs': minor
+---
+
+Update readme, website, add python package and examples
diff --git a/README.md b/README.md
index 623af84..51975cd 100644
--- a/README.md
+++ b/README.md
@@ -5,33 +5,13 @@
# RushDB
### The Instant Database for Modern Apps and DS/ML Ops
-RushDB is an open-source database built on Neo4j, designed to simplify application development.
+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, enabling developers to focus on building features rather than wrestling with data.
[π Homepage](https://rushdb.com) β [π’ Blog](https://rushdb.com/blog) β [βοΈ Platform ](https://app.rushdb.com) β [π Docs](https://docs.rushdb.com) β [π§βπ» Examples](https://github.com/rush-db/examples)
-## π Feature Highlights
-
-### 1. **Data modeling is optional**
-Push data of any shapeβRushDB handles relationships, data types, and more automatically.
-
-### 2. **Automatic type inference**
-Minimizes overhead while optimizing performance for high-speed searches.
-
-### 3. **Powerful search API**
-Query data with accuracy using the graph-powered search API.
-
-### 4. **Flexible data import**
-Easily import data in `JSON`, `CSV`, or `JSONB`, creating data-rich applications fast.
-
-### 5. **Developer-Centric Design**
-RushDB prioritizes DX with an intuitive and consistent API.
-
-### 6. **REST API Readiness**
-A REST API with SDK-like DX for every operation: manage relationships, create, delete, and search effortlessly. Same DTO everywhere.
-
---
## Setup
@@ -123,6 +103,42 @@ Before running the container, ensure you provide the following required environm
---
+
+ Development Setup with local Neo4j [DOCKER COMPOSE]
+
+ ```yaml
+ version: '3.8'
+ services:
+ rushdb:
+ image: rushdb/platform
+ container_name: rushdb
+ depends_on:
+ neo4j:
+ condition: service_healthy
+ ports:
+ - "3000:3000"
+ environment:
+ - NEO4J_URL=bolt://neo4j
+ - NEO4J_USERNAME=neo4j
+ - NEO4J_PASSWORD=password
+ neo4j:
+ image: neo4j:5.25.1
+ healthcheck:
+ test: [ "CMD-SHELL", "wget --no-verbose --tries=1 --spider localhost:7474 || exit 1" ]
+ interval: 5s
+ retries: 30
+ start_period: 10s
+ ports:
+ - "7474:7474"
+ - "7687:7687"
+ environment:
+ - NEO4J_ACCEPT_LICENSE_AGREEMENT=yes
+ - NEO4J_AUTH=neo4j/password
+ - NEO4J_PLUGINS=["apoc"]
+ ```
+
+
+
### **CLI Commands**
The RushDB CLI allows you to manage users in self-hosted installations. Below are the available commands:
@@ -166,8 +182,82 @@ This command updates the password for an existing user identified by the provide
2. **Build Anything**:
Easily push, search, and manage relationships within your data.
+### With Python
+
+Explore the [Documentation](https://docs.rushdb.com/python-sdk/records-api)
+
+#### Install the SDK
+
+```bash
+pip install rushdb
+```
+
+#### Push any json data
+
+```python
+from rushdb import RushDB
+
+db = RushDB(
+ "rushdb-api-key",
+ # Default URL; only override if necessary.
+ base_url="https://api.rushdb.com",
+)
+
+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.",
+ "tags": ["AI", "Cloud Computing", "Research"],
+ "profitable": true,
+ "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",
+ "salary": 3000000,
+ }
+ ],
+ }
+ ],
+ }
+ ],
+ },
+)
+```
+
+#### Find Records by specific criteria
+```python
+# Find Records by specific criteria
+matched_employees = db.records.find(
+ {
+ "labels": ["EMPLOYEE"],
+ "where": {
+ "position": {"$contains": "AI"},
+ "PROJECT": {"DEPARTMENT": {"COMPANY": {"rating": {"$gte": 4}}}},
+ },
+ }
+)
+
+```
+---
+
### With TypeScript / JavaScript
+Explore the [Documentation](https://docs.rushdb.com)
+
#### Install the SDK
```bash
@@ -238,6 +328,8 @@ const company = await db.records.findUniq('COMPANY', {
### With REST API and cURL
+Explore the [Documentation](https://docs.rushdb.com)
+
#### Specify API base URL
- **RushDB Cloud**: `https://api.rushdb.com`
@@ -298,10 +390,6 @@ curl -X POST https://api.rushdb.com/api/v1/records/search \
}'
```
-
-You Rock π
-
-
---
diff --git a/docs/docs/python-sdk/_category_.json b/docs/docs/python-sdk/_category_.json
new file mode 100644
index 0000000..09a9125
--- /dev/null
+++ b/docs/docs/python-sdk/_category_.json
@@ -0,0 +1,6 @@
+{
+ "label": "Python SDK",
+ "position": 3,
+ "collapsed": false,
+ "collapsible": false
+}
diff --git a/docs/docs/python-sdk/properties-api.md b/docs/docs/python-sdk/properties-api.md
new file mode 100644
index 0000000..f600bac
--- /dev/null
+++ b/docs/docs/python-sdk/properties-api.md
@@ -0,0 +1,243 @@
+---
+sidebar_position: 3
+---
+
+# PropertiesAPI
+
+The `PropertiesAPI` class provides methods for managing and querying properties in RushDB.
+
+## Class Definition
+
+```python
+class PropertiesAPI(BaseAPI):
+```
+
+## Methods
+
+### find()
+
+Retrieves a list of properties based on optional search criteria.
+
+**Signature:**
+```python
+def find(
+ self,
+ query: Optional[SearchQuery] = None,
+ transaction: Optional[Transaction] = None
+) -> List[Property]
+```
+
+**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()
+
+# Find properties with specific criteria
+query = {
+ "where": {
+ "name": {"$startsWith": "user_"}, # Properties starting with 'user_'
+ "type": "string" # Only string type properties
+ },
+ "limit": 10 # Limit to 10 results
+}
+filtered_properties = client.properties.find(query)
+```
+
+### find_by_id()
+
+Retrieves a specific property by its ID.
+
+**Signature:**
+```python
+def find_by_id(
+ self,
+ property_id: str,
+ transaction: Optional[Transaction] = None
+) -> Property
+```
+
+**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")
+```
+
+### delete()
+
+Deletes a property by its ID.
+
+**Signature:**
+```python
+def delete(
+ self,
+ property_id: str,
+ transaction: Optional[Transaction] = None
+) -> None
+```
+
+**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")
+```
+
+### values()
+
+Retrieves values for a specific property with optional sorting and pagination.
+
+**Signature:**
+```python
+def values(
+ self,
+ property_id: str,
+ sort: Optional[Literal["asc", "desc"]] = None,
+ skip: Optional[int] = None,
+ limit: Optional[int] = None,
+ transaction: Optional[Transaction] = None
+) -> PropertyValuesData
+```
+
+**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)
+- `limit` (Optional[int]): Maximum number of values to return
+- `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(
+ property_id="prop_age",
+ sort="desc", # Sort values in descending order
+ skip=0, # Start from the first value
+ limit=100 # Return up to 100 values
+)
+
+# Access values
+print(values_data.get('values', [])) # List of property values
+print(values_data.get('min')) # Minimum value (for numeric properties)
+print(values_data.get('max')) # Maximum value (for numeric properties)
+```
+
+## Comprehensive Usage Example
+
+```python
+# Find all properties
+all_properties = client.properties.find()
+for prop in all_properties:
+ print(f"Property ID: {prop['id']}")
+ print(f"Name: {prop['name']}")
+ print(f"Type: {prop['type']}")
+ print(f"Metadata: {prop.get('metadata', 'No metadata')}")
+ print("---")
+
+# Detailed property search
+query = {
+ "where": {
+ "type": "number", # Only numeric properties
+ "name": {"$contains": "score"} # Properties with 'score' in name
+ },
+ "limit": 5 # Limit to 5 results
+}
+numeric_score_properties = client.properties.find(query)
+
+# Get values for a specific property
+if numeric_score_properties:
+ first_prop = numeric_score_properties[0]
+ prop_values = client.properties.values(
+ property_id=first_prop['id'],
+ sort="desc",
+ limit=50
+ )
+ 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'])
+ 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
+- `"number"`: Numeric values
+- `"string"`: Text values
+
+### Property Structure Example
+```python
+property = {
+ "id": "prop_unique_id",
+ "name": "user_score",
+ "type": "number",
+ "metadata": Optional[str] # Optional additional information
+}
+
+property_with_value = {
+ "id": "prop_unique_id",
+ "name": "user_score",
+ "type": "number",
+ "value": 95.5 # Actual property value
+}
+```
+
+## Transactions
+
+Properties API methods support optional transactions for atomic operations:
+
+```python
+# Using a transaction
+with client.transactions.begin() as transaction:
+ # Perform multiple property-related operations
+ property_to_delete = client.properties.find(
+ {"where": {"name": "temp_property"}},
+ transaction=transaction
+ )[0]
+
+ client.properties.delete(
+ property_id=property_to_delete['id'],
+ transaction=transaction
+ )
+ # Transaction will automatically commit if no errors occur
+```
+
+## Error Handling
+
+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")
+except RushDBError as e:
+ print(f"Error: {e}")
+ print(f"Error Details: {e.details}")
+```
diff --git a/docs/docs/python-sdk/record.md b/docs/docs/python-sdk/record.md
new file mode 100644
index 0000000..cc41390
--- /dev/null
+++ b/docs/docs/python-sdk/record.md
@@ -0,0 +1,338 @@
+---
+sidebar_position: 2
+---
+
+# Record
+
+The `Record` class represents a record in RushDB and provides methods for manipulating individual records, including updates, relationships, and deletions.
+
+## Class Definition
+
+```python
+class Record:
+ def __init__(self, client: "RushDB", data: Union[Dict[str, Any], None] = None)
+```
+
+## Properties
+
+### id
+
+Gets the record's unique identifier.
+
+**Type:** `str`
+
+**Example:**
+```python
+record = client.records.create("USER", {"name": "John"})
+print(record.id) # e.g., "1234abcd-5678-..."
+```
+
+### proptypes
+
+Gets the record's property types.
+
+**Type:** `str`
+
+**Example:**
+```python
+record = client.records.create("USER", {"name": "John", "age": 25})
+print(record.proptypes) # Returns property type definitions
+```
+
+### label
+
+Gets the record's label.
+
+**Type:** `str`
+
+**Example:**
+```python
+record = client.records.create("USER", {"name": "John"})
+print(record.label) # "USER"
+```
+
+### timestamp
+
+Gets the record's creation timestamp from its ID.
+
+**Type:** `int`
+
+**Example:**
+```python
+record = client.records.create("USER", {"name": "John"})
+print(record.timestamp) # Unix timestamp in milliseconds
+```
+
+### date
+
+Gets the record's creation date.
+
+**Type:** `datetime`
+
+**Example:**
+```python
+record = client.records.create("USER", {"name": "John"})
+print(record.date) # datetime object
+```
+
+## Methods
+
+### set()
+
+Updates all data for the record.
+
+**Signature:**
+```python
+def set(
+ self,
+ data: Dict[str, Any],
+ transaction: Optional[Transaction] = None
+) -> Dict[str, str]
+```
+
+**Arguments:**
+- `data` (Dict[str, Any]): New record data
+- `transaction` (Optional[Transaction]): Optional transaction object
+
+**Returns:**
+- `Dict[str, str]`: Response data
+
+**Example:**
+```python
+record = client.records.create("USER", {"name": "John"})
+response = record.set({
+ "name": "John Doe",
+ "email": "john@example.com",
+ "age": 30
+})
+```
+
+### update()
+
+Updates specific fields of the record.
+
+**Signature:**
+```python
+def update(
+ self,
+ data: Dict[str, Any],
+ transaction: Optional[Transaction] = None
+) -> Dict[str, str]
+```
+
+**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 = client.records.create("USER", {
+ "name": "John",
+ "email": "john@example.com"
+})
+response = record.update({
+ "email": "john.doe@example.com"
+})
+```
+
+### attach()
+
+Creates relationships with other records.
+
+**Signature:**
+```python
+def attach(
+ self,
+ target: Union[str, List[str], Dict[str, Any], List[Dict[str, Any]], "Record", List["Record"]],
+ options: Optional[RelationshipOptions] = None,
+ transaction: Optional[Transaction] = None
+) -> Dict[str, str]
+```
+
+**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
+ - `type` (Optional[str]): Relationship type
+- `transaction` (Optional[Transaction]): Optional transaction object
+
+**Returns:**
+- `Dict[str, str]`: Response data
+
+**Example:**
+```python
+# Create two records
+user = client.records.create("USER", {"name": "John"})
+group = client.records.create("GROUP", {"name": "Admins"})
+
+# Attach user to group
+response = user.attach(
+ target=group,
+ options=RelationshipOptions(
+ type="BELONGS_TO",
+ direction="out"
+ )
+)
+```
+
+### detach()
+
+Removes relationships with other records.
+
+**Signature:**
+```python
+def detach(
+ self,
+ target: Union[str, List[str], Dict[str, Any], List[Dict[str, Any]], "Record", List["Record"]],
+ options: Optional[RelationshipDetachOptions] = None,
+ transaction: Optional[Transaction] = None
+) -> Dict[str, str]
+```
+
+**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
+ - `typeOrTypes` (Optional[Union[str, List[str]]]): Relationship type(s)
+- `transaction` (Optional[Transaction]): Optional transaction object
+
+**Returns:**
+- `Dict[str, str]`: Response data
+
+**Example:**
+```python
+# Detach user from group
+response = user.detach(
+ target=group,
+ options=RelationshipDetachOptions(
+ typeOrTypes="BELONGS_TO",
+ direction="out"
+ )
+)
+```
+
+### delete()
+
+Deletes the record.
+
+**Signature:**
+```python
+def delete(
+ self,
+ transaction: Optional[Transaction] = None
+) -> Dict[str, str]
+```
+
+**Arguments:**
+- `transaction` (Optional[Transaction]): Optional transaction object
+
+**Returns:**
+- `Dict[str, str]`: Response data
+
+**Example:**
+```python
+user = client.records.create("USER", {"name": "John"})
+response = user.delete()
+```
+
+## Complete Usage Example
+
+Here's a comprehensive example demonstrating various Record operations:
+
+```python
+# Create a new record
+user = client.records.create("USER", {
+ "name": "John Doe",
+ "email": "john@example.com",
+ "age": 30
+})
+
+# Access properties
+print(f"Record ID: {user.id}")
+print(f"Label: {user.label}")
+print(f"Created at: {user.date}")
+
+# Update record data
+user.update({
+ "age": 31,
+ "title": "Senior Developer"
+})
+
+# Create related records
+department = client.records.create("DEPARTMENT", {
+ "name": "Engineering"
+})
+
+project = client.records.create("PROJECT", {
+ "name": "Secret Project"
+})
+
+# Create relationships
+user.attach(
+ target=department,
+ options=RelationshipOptions(
+ type="BELONGS_TO",
+ direction="out"
+ )
+)
+
+user.attach(
+ target=project,
+ options=RelationshipOptions(
+ type="WORKS_ON",
+ direction="out"
+ )
+)
+
+# Remove relationship
+user.detach(
+ target=project,
+ options=RelationshipDetachOptions(
+ typeOrTypes="WORKS_ON",
+ direction="out"
+ )
+)
+
+# Delete record
+user.delete()
+```
+
+## Working with Transactions
+
+Records can be manipulated within transactions for atomic operations:
+
+```python
+# Start a transaction
+with client.transactions.begin() as transaction:
+ # Create user
+ user = client.records.create(
+ "USER",
+ {"name": "John Doe"},
+ transaction=transaction
+ )
+
+ # Update user
+ user.update(
+ {"status": "active"},
+ transaction=transaction
+ )
+
+ # Create and attach department
+ dept = client.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
+```
diff --git a/docs/docs/python-sdk/records-api.md b/docs/docs/python-sdk/records-api.md
new file mode 100644
index 0000000..438dfd2
--- /dev/null
+++ b/docs/docs/python-sdk/records-api.md
@@ -0,0 +1,406 @@
+---
+sidebar_position: 1
+---
+
+# RecordsAPI
+
+The `RecordsAPI` class provides methods for managing records in RushDB. It handles record creation, updates, deletion, searching, and relationship management.
+
+## Class Definition
+
+```python
+class RecordsAPI(BaseAPI):
+```
+
+## 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 = client.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 = client.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,
+ record_id: str,
+ data: Dict[str, Any],
+ transaction: Optional[Transaction] = None
+) -> Dict[str, str]
+```
+
+**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 = {
+ "name": "Updated Company Name",
+ "rating": 5.0
+}
+
+response = client.records.set(
+ record_id="record-123",
+ data=new_data
+)
+```
+
+### update()
+
+Updates specific fields of a record by ID.
+
+**Signature:**
+```python
+def update(
+ self,
+ record_id: str,
+ data: Dict[str, Any],
+ transaction: Optional[Transaction] = None
+) -> Dict[str, str]
+```
+
+**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 = {
+ "rating": 4.8,
+ "status": "active"
+}
+
+response = client.records.update(
+ record_id="record-123",
+ data=updates
+)
+```
+
+### find()
+
+Searches for records matching specified criteria.
+
+**Signature:**
+```python
+def find(
+ self,
+ query: Optional[SearchQuery] = None,
+ record_id: Optional[str] = None,
+ transaction: Optional[Transaction] = None
+) -> List[Record]
+```
+
+**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 = {
+ "where": {
+ "$and": [
+ {"age": {"$gte": 18}},
+ {"status": "active"},
+ {"department": "Engineering"}
+ ]
+ },
+ "orderBy": {"created_at": "desc"},
+ "limit": 10
+}
+
+records = client.records.find(query=query)
+```
+
+### delete()
+
+Deletes records matching a query.
+
+**Signature:**
+```python
+def delete(
+ self,
+ query: SearchQuery,
+ transaction: Optional[Transaction] = None
+) -> Dict[str, str]
+```
+
+**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 = {
+ "where": {
+ "status": "inactive",
+ "lastActive": {"$lt": "2023-01-01"}
+ }
+}
+
+response = client.records.delete(query)
+```
+
+### delete_by_id()
+
+Deletes one or more records by ID.
+
+**Signature:**
+```python
+def delete_by_id(
+ self,
+ id_or_ids: Union[str, List[str]],
+ transaction: Optional[Transaction] = None
+) -> Dict[str, str]
+```
+
+**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 = client.records.delete_by_id("record-123")
+
+# Delete multiple records
+response = client.records.delete_by_id([
+ "record-123",
+ "record-456",
+ "record-789"
+])
+```
+
+### attach()
+
+Creates relationships between records.
+
+**Signature:**
+```python
+def attach(
+ self,
+ source: Union[str, Dict[str, Any]],
+ target: Union[str, List[str], Dict[str, Any], List[Dict[str, Any]], Record, List[Record]],
+ options: Optional[RelationshipOptions] = None,
+ transaction: Optional[Transaction] = None
+) -> Dict[str, str]
+```
+
+**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
+ - `direction` (Optional[Literal["in", "out"]]): Relationship direction
+ - `type` (Optional[str]): Relationship type
+- `transaction` (Optional[Transaction]): Optional transaction object
+
+**Returns:**
+- `Dict[str, str]`: Response data
+
+**Example:**
+```python
+# Create relationship between records
+options = RelationshipOptions(
+ type="HAS_EMPLOYEE",
+ direction="out"
+)
+
+response = client.records.attach(
+ source="company-123",
+ target=["employee-456", "employee-789"],
+ options=options
+)
+```
+
+### detach()
+
+Removes relationships between records.
+
+**Signature:**
+```python
+def detach(
+ self,
+ source: Union[str, Dict[str, Any]],
+ target: Union[str, List[str], Dict[str, Any], List[Dict[str, Any]], Record, List[Record]],
+ options: Optional[RelationshipDetachOptions] = None,
+ transaction: Optional[Transaction] = None
+) -> Dict[str, str]
+```
+
+**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
+ - `direction` (Optional[Literal["in", "out"]]): Relationship direction
+ - `typeOrTypes` (Optional[Union[str, List[str]]]): Relationship type(s)
+- `transaction` (Optional[Transaction]): Optional transaction object
+
+**Returns:**
+- `Dict[str, str]`: Response data
+
+**Example:**
+```python
+# Remove relationships between records
+options = RelationshipDetachOptions(
+ typeOrTypes=["HAS_EMPLOYEE", "MANAGES"],
+ direction="out"
+)
+
+response = client.records.detach(
+ source="company-123",
+ target="employee-456",
+ options=options
+)
+```
+
+### import_csv()
+
+Imports records from CSV data.
+
+**Signature:**
+```python
+def import_csv(
+ self,
+ label: str,
+ csv_data: Union[str, bytes],
+ options: Optional[Dict[str, bool]] = None,
+ transaction: Optional[Transaction] = None
+) -> List[Dict[str, Any]]
+```
+
+**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
+John Doe,30,Engineering,Senior Engineer
+Jane Smith,28,Product,Product Manager
+Bob Wilson,35,Engineering,Tech Lead"""
+
+records = client.records.import_csv(
+ label="EMPLOYEE",
+ csv_data=csv_data,
+ options={"returnResult": True, "suggestTypes": True}
+)
+```
diff --git a/packages/javascript-sdk/README.md b/packages/javascript-sdk/README.md
index 44bab4c..0e1f215 100644
--- a/packages/javascript-sdk/README.md
+++ b/packages/javascript-sdk/README.md
@@ -5,7 +5,7 @@
# RushDB SDK for JavaScript and TypeScript
[](https://www.npmjs.com/package/@rushdb/javascript-sdk)
-[](#license "Go to license section")
+[](#license "Go to license section")


diff --git a/platform/core/README.md b/platform/core/README.md
index 87f6b63..9e282aa 100644
--- a/platform/core/README.md
+++ b/platform/core/README.md
@@ -12,6 +12,8 @@ It streamlines application development by automating data normalization, managin
[π Homepage](https://rushdb.com) β [π’ Blog](https://rushdb.com/blog) β [βοΈ Platform ](https://app.rushdb.com) β [π Docs](https://docs.rushdb.com) β [π§βπ» Examples](https://github.com/rush-db/examples)
+---
+
## Prerequisites
Before running the application, ensure that you have the following installed:
diff --git a/platform/dashboard/README.md b/platform/dashboard/README.md
index 8e440a1..d768293 100644
--- a/platform/dashboard/README.md
+++ b/platform/dashboard/README.md
@@ -12,6 +12,8 @@ It streamlines application development by automating data normalization, managin
[π Homepage](https://rushdb.com) β [π’ Blog](https://rushdb.com/blog) β [βοΈ Platform ](https://app.rushdb.com) β [π Docs](https://docs.rushdb.com) β [π§βπ» Examples](https://github.com/rush-db/examples)
+---
+
The `/platform/dashboard` directory contains the RushDB management interface, built with React and Vite. This README provides instructions for running, building, and configuring the dashboard both as a standalone app and as part of the core RushDB platform.
## Prerequisites
diff --git a/website/public/sitemap-0.xml b/website/public/sitemap-0.xml
index 597a325..844e540 100644
--- a/website/public/sitemap-0.xml
+++ b/website/public/sitemap-0.xml
@@ -1,9 +1,9 @@
-https://rushdb.com2025-01-31T13:06:30.667Zdaily0.7
-https://rushdb.com/blog2025-01-31T13:06:30.668Zdaily0.7
-https://rushdb.com/pricing2025-01-31T13:06:30.668Zdaily0.7
-https://rushdb.com/cookie-policy2025-01-31T13:06:30.668Zdaily0.7
-https://rushdb.com/privacy-policy2025-01-31T13:06:30.668Zdaily0.7
-https://rushdb.com/terms-of-service2025-01-31T13:06:30.668Zdaily0.7
+https://rushdb.com2025-02-03T18:13:22.179Zdaily0.7
+https://rushdb.com/blog2025-02-03T18:13:22.179Zdaily0.7
+https://rushdb.com/pricing2025-02-03T18:13:22.179Zdaily0.7
+https://rushdb.com/cookie-policy2025-02-03T18:13:22.179Zdaily0.7
+https://rushdb.com/privacy-policy2025-02-03T18:13:22.179Zdaily0.7
+https://rushdb.com/terms-of-service2025-02-03T18:13:22.179Zdaily0.7
\ No newline at end of file
diff --git a/website/src/components/CodeBlock.tsx b/website/src/components/CodeBlock.tsx
index 608fa5b..5c2840d 100644
--- a/website/src/components/CodeBlock.tsx
+++ b/website/src/components/CodeBlock.tsx
@@ -1,17 +1,9 @@
-import { CSSProperties, PropsWithoutRef, forwardRef, useState, ReactNode, Children } from 'react'
-import {
- materialDark as codeTheme
- // atomDark,
- // nightOwl,
- // synthwave84,
- // tomorrow,
-} from 'react-syntax-highlighter/dist/cjs/styles/prism'
+import { CSSProperties, PropsWithoutRef, forwardRef, ReactNode, Children } from 'react'
+import { materialDark as codeTheme } from 'react-syntax-highlighter/dist/cjs/styles/prism'
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
import classNames from 'classnames'
import cx from 'classnames'
-import { copyToClipboard } from '~/utils/copyToClipboard'
-import { CopyCheck, CopyIcon } from 'lucide-react'
-import { Button } from '~/components/Button'
+
import { CopyButton } from '~/components/CopyButton'
const PreStyles: CSSProperties = {
diff --git a/website/src/components/CodeBlockWithLanguageSelector.tsx b/website/src/components/CodeBlockWithLanguageSelector.tsx
new file mode 100644
index 0000000..0f6fb0e
--- /dev/null
+++ b/website/src/components/CodeBlockWithLanguageSelector.tsx
@@ -0,0 +1,131 @@
+import { CSSProperties, PropsWithoutRef, forwardRef, ReactNode, useContext } from 'react'
+
+import { CodingLanguage } from '~/pages'
+import { CodeBlock } from '~/components/CodeBlock'
+import { Tabs, TabsContent, TabsList } from '~/components/Tabs'
+import { TabsTrigger } from '@radix-ui/react-tabs'
+import cn from 'classnames'
+
+type CodeBlockWithLanguageSelectorProps = {
+ data: Record
+ className?: string
+ wrapperClassName?: string
+ preClassName?: string
+ style?: CSSProperties
+ children?: ReactNode
+ copyButton?: boolean
+}
+
+const PyLogo = ({ className }: { className: string }) => (
+
+)
+const TsLogo = ({ className }: { className: string }) => (
+
+)
+
+const langLogoMap = {
+ python: PyLogo,
+ typescript: TsLogo
+}
+
+const Logo = ({ lang, className }: { lang: string; className: string }) => {
+ // @ts-ignore
+ const Comp = langLogoMap[lang]
+
+ return
+}
+
+export const CodeBlockWithLanguageSelector = forwardRef<
+ HTMLDivElement,
+ PropsWithoutRef
+>(({ data, className, preClassName, wrapperClassName, children: extra, copyButton, style }, ref) => {
+ const { language, setLanguage } = useContext(CodingLanguage)
+
+ return (
+
+
+ {Object.keys(data).map((key) => (
+
setLanguage(key)}
+ className={cn('w-full grow py-2 transition hover:grayscale-0', {
+ grayscale: key !== language,
+ 'border-b': key === language,
+ 'text-content3': key !== language
+ })}
+ >
+ {key}
+
+ ))}
+
+
+
+ {extra}
+
+
+ )
+})
+
+CodeBlockWithLanguageSelector.displayName = 'CodeBlockWithLanguageSelector'
diff --git a/website/src/pages/index.tsx b/website/src/pages/index.tsx
index 548555d..8949bc8 100644
--- a/website/src/pages/index.tsx
+++ b/website/src/pages/index.tsx
@@ -3,13 +3,27 @@ import { Hero } from '~/sections/Hero'
import { Mission } from '~/sections/Mission'
import { HowItWorks } from '~/sections/HowItWorks'
+import { createContext, useState } from 'react'
+
+export const CodingLanguage = createContext<{ language: string; setLanguage: (value: string) => void }>({
+ language: 'typescript',
+ setLanguage: (value: string) => {}
+})
export default function Home() {
+ const [language, setLanguage] = useState('typescript')
return (
-
-
-
-
-
+
+
+
+
+
+
+
)
}
diff --git a/website/src/sections/Hero/index.tsx b/website/src/sections/Hero/index.tsx
index d4eb34b..76e929e 100644
--- a/website/src/sections/Hero/index.tsx
+++ b/website/src/sections/Hero/index.tsx
@@ -6,6 +6,9 @@ import { Button, MainCta } from '~/components/Button'
import { links, socials } from '~/config/urls'
import { CodeBlock } from '~/components/CodeBlock'
import { GitHub } from '~/components/Icons/GitHub'
+import { CodeBlockWithLanguageSelector } from '~/components/CodeBlockWithLanguageSelector'
+import { useContext } from 'react'
+import { CodingLanguage } from '~/pages'
const code = `import RushDB from '@rushdb/javascript-sdk'
@@ -29,7 +32,35 @@ await db.records.find({
}
})`
+const codePy = `from rushdb import RushDB
+
+db = RushDB("API_TOKEN")
+
+user = db.records.create(
+ "USER",
+ {
+ "name": "Paul Schmitz",
+ "lastActive": "2024-12-02T11:38:29Z",
+ "verified": True,
+ "size": 9.5,
+ "favoriteTags": ["Daily Run", "Foam"]
+ }
+)
+
+db.records.find(
+ {
+ "labels": ["USER"],
+ "where": {
+ "size": {"$gte": 9},
+ "favoriteTags": {"$in": ["Foam"]}
+ }
+ }
+)
+`
+
export const Hero = () => {
+ const { language } = useContext(CodingLanguage)
+
return (
<>
@@ -73,8 +104,11 @@ export const Hero = () => {
-
@@ -85,13 +119,17 @@ export const Hero = () => {
RushDB is an open-source, graph-powered zero-config database
diff --git a/website/src/sections/HowItWorks/index.tsx b/website/src/sections/HowItWorks/index.tsx
index da2ed44..5d4f851 100644
--- a/website/src/sections/HowItWorks/index.tsx
+++ b/website/src/sections/HowItWorks/index.tsx
@@ -7,6 +7,9 @@ import { CodeBlock } from '~/components/CodeBlock'
import Image from 'next/image'
import dashboard from '../../images/dashboard.png'
+import { CodeBlockWithLanguageSelector } from '~/components/CodeBlockWithLanguageSelector'
+import { useContext } from 'react'
+import { CodingLanguage } from '~/pages'
const code1 = `import RushDB from '@rushdb/javascript-sdk'
const db = new RushDB('rushdb-api-key')
@@ -32,6 +35,36 @@ await db.records.createMany("COMPANY", {
email: 'jeff@google.com',
salary: 3000000`
+const code1Py = `from rushdb import RushDB
+
+db = RushDB("rushdb-api-key")
+
+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.",
+ "tags": ["AI", "Cloud Computing", "Research"],
+ "profitable": true,
+ "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",
+ "salary": 3000000"`
+
const code2 = `await db.records.find({
labels: ['COMPANY'],
where: {
@@ -59,6 +92,33 @@ const code2 = `await db.records.find({
}
})`
+const code2Py = `db.records.find(
+ {
+ "labels": ["COMPANY"],
+ "where": {
+ "stage": "seed",
+ "address": {"$contains": "USA"},
+ "foundedAt": {"$year": {"$lte": 2000}},
+ "rating": {
+ "$or": [{"$lt": 2.5}, {"$gte": 4.5}]
+ },
+ "EMPLOYEE": {
+ "$alias": "$employee",
+ "salary": {
+ "$gte": 500_000
+ }
+ },
+ },
+ "aggregate": {
+ "employees": {
+ "fn": "collect",
+ "alias": "$employee",
+ "limit": 10
+ }
+ },
+ }
+)`
+
const code3 = `// Property \`name\` [string]
await db.properties.values(
'0192397b-8579-7ce2-a899-01c59bad63f8'
@@ -87,6 +147,34 @@ await db.properties.values(
}
`
+const code3Py = `# Property \`name\` [string]
+db.properties.values(
+ "0192397b-8579-7ce2-a899-01c59bad63f8"
+)
+# Response
+{
+ "values": [
+ "Eleanor Whitaker",
+ "Marcus Donovan",
+ "Priya Kapoor",
+ "Julian Alvarez"
+ ],
+ "type": "string"
+}
+
+# Property \`size\` [number]
+db.properties.values(
+ "019412c0-2051-71fe-bc9d-26117b52c119"
+)
+# Response
+{
+ "min": 5.5,
+ "max": 12.5,
+ "values": [5.5, 6, 6.5, 7, 7.5, 8, 8.5, ...],
+ "type": "number"
+}
+`
+
const codeDocker = `docker run -p 3000:3000 --name rushdb \\
-e NEO4J_URL='neo4j+s://1234567.databases.neo4j.io' \\
-e NEO4J_USERNAME='neo4j' \\
@@ -152,7 +240,32 @@ async function generateAndStoreData() {
)
}`
+const codeAiIntegrationPy = `import openai
+from rushdb import RushDB
+
+db = RushDB("rushdb-api-key")
+openai.api_key = "openai-api-key"
+
+
+def generate_and_store_data():
+ # Step 1: Call OpenAI API to generate some output
+ prompt = "..."
+ completion = await openai.ChatCompletion.create(
+ model="gpt-3.5-turbo",
+ messages=[{"role": "user", "content": prompt}],
+ response_format={"type": "json_object"},
+ )
+
+ # Step 2: Extract the generated content
+ generated_content = completion["choices"][0]["message"]["content"]
+ parsed_content = json.loads(generated_content)
+
+ # Step 3: Store the output in RushDB
+ record = await db.records.create_many("AI_RESPONSE", parsed_content)`
+
export const HowItWorks = () => {
+ const { language } = useContext(CodingLanguage)
+
return (
<>
@@ -170,7 +283,7 @@ export const HowItWorks = () => {
and labels any input data, so you donβt have to.
{
complex, deeply interconnected data without the acrobatics.
-
+ >
@@ -328,12 +441,12 @@ export const HowItWorks = () => {
backend, no fuss. All from a single API.
-
+ >
@@ -370,8 +483,8 @@ export const HowItWorks = () => {
-