Initial commit: MCP Hub Community Edition v3.0.0
Community edition generated from private repo via sync pipeline. Includes 9 plugins (WordPress, WooCommerce, WP Advanced, Gitea, n8n, Supabase, OpenPanel, Appwrite, Directus) with ~587 tools. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
752
plugins/appwrite/handlers/documents.py
Normal file
752
plugins/appwrite/handlers/documents.py
Normal file
@@ -0,0 +1,752 @@
|
||||
"""
|
||||
Documents Handler - manages Appwrite document CRUD operations
|
||||
|
||||
Phase I.1: 12 tools
|
||||
- Documents CRUD: 5 (list, get, create, update, delete)
|
||||
- Bulk Operations: 3 (bulk_create, bulk_update, bulk_delete)
|
||||
- Query/Count: 4 (search, count, get_by_query, list_with_cursor)
|
||||
"""
|
||||
|
||||
import json
|
||||
from typing import Any
|
||||
|
||||
from plugins.appwrite.client import AppwriteClient
|
||||
|
||||
# =====================
|
||||
# QUERY HELPERS (Appwrite 1.7.4 JSON format)
|
||||
# =====================
|
||||
|
||||
def _query_limit(value: int) -> str:
|
||||
"""Build limit query in JSON format."""
|
||||
return json.dumps({"method": "limit", "values": [value]})
|
||||
|
||||
def _query_offset(value: int) -> str:
|
||||
"""Build offset query in JSON format."""
|
||||
return json.dumps({"method": "offset", "values": [value]})
|
||||
|
||||
def _query_order_asc(attribute: str) -> str:
|
||||
"""Build orderAsc query in JSON format."""
|
||||
return json.dumps({"method": "orderAsc", "values": [attribute]})
|
||||
|
||||
def _query_order_desc(attribute: str) -> str:
|
||||
"""Build orderDesc query in JSON format."""
|
||||
return json.dumps({"method": "orderDesc", "values": [attribute]})
|
||||
|
||||
def _query_cursor_after(document_id: str) -> str:
|
||||
"""Build cursorAfter query in JSON format."""
|
||||
return json.dumps({"method": "cursorAfter", "values": [document_id]})
|
||||
|
||||
def _query_cursor_before(document_id: str) -> str:
|
||||
"""Build cursorBefore query in JSON format."""
|
||||
return json.dumps({"method": "cursorBefore", "values": [document_id]})
|
||||
|
||||
def _query_search(attribute: str, value: str) -> str:
|
||||
"""Build search query in JSON format."""
|
||||
return json.dumps({"method": "search", "attribute": attribute, "values": [value]})
|
||||
|
||||
def _query_equal(attribute: str, values: list[Any]) -> str:
|
||||
"""Build equal query in JSON format."""
|
||||
return json.dumps({"method": "equal", "attribute": attribute, "values": values})
|
||||
|
||||
def get_tool_specifications() -> list[dict[str, Any]]:
|
||||
"""Return tool specifications for ToolGenerator (12 tools)"""
|
||||
return [
|
||||
# =====================
|
||||
# DOCUMENT CRUD (5)
|
||||
# =====================
|
||||
{
|
||||
"name": "list_documents",
|
||||
"method_name": "list_documents",
|
||||
"description": """List documents in a collection with powerful query support.
|
||||
|
||||
Queries must be JSON objects (Appwrite 1.7.4 format):
|
||||
- {"method": "equal", "attribute": "status", "values": ["active"]}
|
||||
- {"method": "notEqual", "attribute": "type", "values": ["draft"]}
|
||||
- {"method": "greaterThan", "attribute": "price", "values": [100]}
|
||||
- {"method": "search", "attribute": "title", "values": ["keyword"]}
|
||||
- {"method": "orderAsc", "values": ["createdAt"]}
|
||||
- {"method": "orderDesc", "values": ["createdAt"]}
|
||||
- {"method": "limit", "values": [25]}
|
||||
- {"method": "offset", "values": [50]}
|
||||
- {"method": "cursorAfter", "values": ["documentId"]}""",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"database_id": {"type": "string", "description": "Database ID"},
|
||||
"collection_id": {"type": "string", "description": "Collection ID"},
|
||||
"queries": {
|
||||
"anyOf": [{"type": "array", "items": {"type": "string"}}, {"type": "null"}],
|
||||
"description": "Query JSON strings for filtering, sorting, and pagination",
|
||||
"examples": [
|
||||
[
|
||||
'{"method":"equal","attribute":"status","values":["active"]}',
|
||||
'{"method":"limit","values":[25]}',
|
||||
]
|
||||
],
|
||||
},
|
||||
},
|
||||
"required": ["database_id", "collection_id"],
|
||||
},
|
||||
"scope": "read",
|
||||
},
|
||||
{
|
||||
"name": "get_document",
|
||||
"method_name": "get_document",
|
||||
"description": "Get a single document by ID.",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"database_id": {"type": "string", "description": "Database ID"},
|
||||
"collection_id": {"type": "string", "description": "Collection ID"},
|
||||
"document_id": {"type": "string", "description": "Document ID"},
|
||||
"queries": {
|
||||
"anyOf": [{"type": "array", "items": {"type": "string"}}, {"type": "null"}],
|
||||
"description": "Optional queries for selecting specific attributes",
|
||||
},
|
||||
},
|
||||
"required": ["database_id", "collection_id", "document_id"],
|
||||
},
|
||||
"scope": "read",
|
||||
},
|
||||
{
|
||||
"name": "create_document",
|
||||
"method_name": "create_document",
|
||||
"description": "Create a new document. Use 'unique()' as document_id for auto-generated ID.",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"database_id": {"type": "string", "description": "Database ID"},
|
||||
"collection_id": {"type": "string", "description": "Collection ID"},
|
||||
"document_id": {
|
||||
"type": "string",
|
||||
"description": "Unique document ID. Use 'unique()' for auto-generation",
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"description": "Document data (key-value pairs matching collection attributes)",
|
||||
},
|
||||
"permissions": {
|
||||
"anyOf": [{"type": "array", "items": {"type": "string"}}, {"type": "null"}],
|
||||
"description": "Document permissions (e.g., 'read(\"user:123\")', 'write(\"team:456\")')",
|
||||
},
|
||||
},
|
||||
"required": ["database_id", "collection_id", "document_id", "data"],
|
||||
},
|
||||
"scope": "write",
|
||||
},
|
||||
{
|
||||
"name": "update_document",
|
||||
"method_name": "update_document",
|
||||
"description": "Update an existing document. Only provided fields will be updated.",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"database_id": {"type": "string", "description": "Database ID"},
|
||||
"collection_id": {"type": "string", "description": "Collection ID"},
|
||||
"document_id": {"type": "string", "description": "Document ID"},
|
||||
"data": {
|
||||
"anyOf": [{"type": "object"}, {"type": "null"}],
|
||||
"description": "Fields to update",
|
||||
},
|
||||
"permissions": {
|
||||
"anyOf": [{"type": "array", "items": {"type": "string"}}, {"type": "null"}],
|
||||
"description": "New permissions (replaces existing)",
|
||||
},
|
||||
},
|
||||
"required": ["database_id", "collection_id", "document_id"],
|
||||
},
|
||||
"scope": "write",
|
||||
},
|
||||
{
|
||||
"name": "delete_document",
|
||||
"method_name": "delete_document",
|
||||
"description": "Delete a document by ID.",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"database_id": {"type": "string", "description": "Database ID"},
|
||||
"collection_id": {"type": "string", "description": "Collection ID"},
|
||||
"document_id": {"type": "string", "description": "Document ID to delete"},
|
||||
},
|
||||
"required": ["database_id", "collection_id", "document_id"],
|
||||
},
|
||||
"scope": "write",
|
||||
},
|
||||
# =====================
|
||||
# BULK OPERATIONS (3)
|
||||
# =====================
|
||||
{
|
||||
"name": "bulk_create_documents",
|
||||
"method_name": "bulk_create_documents",
|
||||
"description": """Create multiple documents at once. More efficient than creating one by one.
|
||||
|
||||
Example documents array:
|
||||
[
|
||||
{"document_id": "unique()", "data": {"title": "Doc 1", "status": "active"}},
|
||||
{"document_id": "doc-2", "data": {"title": "Doc 2", "status": "draft"}, "permissions": ["read(\\"any\\")"]}
|
||||
]
|
||||
|
||||
Each document must have:
|
||||
- document_id: Use 'unique()' for auto-generated ID or provide your own
|
||||
- data: Object with field values matching collection attributes""",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"database_id": {"type": "string", "description": "Database ID"},
|
||||
"collection_id": {"type": "string", "description": "Collection ID"},
|
||||
"documents": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"document_id": {
|
||||
"type": "string",
|
||||
"description": "Document ID. Use 'unique()' for auto-generation",
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"description": "Document data (key-value pairs matching collection attributes)",
|
||||
},
|
||||
"permissions": {
|
||||
"anyOf": [
|
||||
{"type": "array", "items": {"type": "string"}},
|
||||
{"type": "null"},
|
||||
],
|
||||
"description": "Optional permissions for this document",
|
||||
},
|
||||
},
|
||||
"required": ["document_id", "data"],
|
||||
},
|
||||
"description": "Array of documents to create. Each must have document_id and data.",
|
||||
},
|
||||
},
|
||||
"required": ["database_id", "collection_id", "documents"],
|
||||
},
|
||||
"scope": "write",
|
||||
},
|
||||
{
|
||||
"name": "bulk_update_documents",
|
||||
"method_name": "bulk_update_documents",
|
||||
"description": "Update multiple documents at once.",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"database_id": {"type": "string", "description": "Database ID"},
|
||||
"collection_id": {"type": "string", "description": "Collection ID"},
|
||||
"updates": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"document_id": {"type": "string"},
|
||||
"data": {"type": "object"},
|
||||
"permissions": {
|
||||
"anyOf": [
|
||||
{"type": "array", "items": {"type": "string"}},
|
||||
{"type": "null"},
|
||||
]
|
||||
},
|
||||
},
|
||||
"required": ["document_id", "data"],
|
||||
},
|
||||
"description": "Array of document updates",
|
||||
},
|
||||
},
|
||||
"required": ["database_id", "collection_id", "updates"],
|
||||
},
|
||||
"scope": "write",
|
||||
},
|
||||
{
|
||||
"name": "bulk_delete_documents",
|
||||
"method_name": "bulk_delete_documents",
|
||||
"description": "Delete multiple documents at once.",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"database_id": {"type": "string", "description": "Database ID"},
|
||||
"collection_id": {"type": "string", "description": "Collection ID"},
|
||||
"document_ids": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "Array of document IDs to delete",
|
||||
},
|
||||
},
|
||||
"required": ["database_id", "collection_id", "document_ids"],
|
||||
},
|
||||
"scope": "write",
|
||||
},
|
||||
# =====================
|
||||
# QUERY/SEARCH (4)
|
||||
# =====================
|
||||
{
|
||||
"name": "search_documents",
|
||||
"method_name": "search_documents",
|
||||
"description": "Full-text search in documents. Requires a fulltext index on the searched attribute.",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"database_id": {"type": "string", "description": "Database ID"},
|
||||
"collection_id": {"type": "string", "description": "Collection ID"},
|
||||
"attribute": {
|
||||
"type": "string",
|
||||
"description": "Attribute name to search in (must have fulltext index)",
|
||||
},
|
||||
"query": {"type": "string", "description": "Search query string"},
|
||||
"limit": {"type": "integer", "description": "Maximum results", "default": 25},
|
||||
},
|
||||
"required": ["database_id", "collection_id", "attribute", "query"],
|
||||
},
|
||||
"scope": "read",
|
||||
},
|
||||
{
|
||||
"name": "count_documents",
|
||||
"method_name": "count_documents",
|
||||
"description": "Count documents in a collection with optional filters.",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"database_id": {"type": "string", "description": "Database ID"},
|
||||
"collection_id": {"type": "string", "description": "Collection ID"},
|
||||
"queries": {
|
||||
"anyOf": [{"type": "array", "items": {"type": "string"}}, {"type": "null"}],
|
||||
"description": "Optional filter queries",
|
||||
},
|
||||
},
|
||||
"required": ["database_id", "collection_id"],
|
||||
},
|
||||
"scope": "read",
|
||||
},
|
||||
{
|
||||
"name": "get_documents_by_ids",
|
||||
"method_name": "get_documents_by_ids",
|
||||
"description": "Get multiple documents by their IDs.",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"database_id": {"type": "string", "description": "Database ID"},
|
||||
"collection_id": {"type": "string", "description": "Collection ID"},
|
||||
"document_ids": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "Array of document IDs to fetch",
|
||||
},
|
||||
},
|
||||
"required": ["database_id", "collection_id", "document_ids"],
|
||||
},
|
||||
"scope": "read",
|
||||
},
|
||||
{
|
||||
"name": "list_documents_paginated",
|
||||
"method_name": "list_documents_paginated",
|
||||
"description": "List documents with cursor-based pagination for efficient large dataset traversal.",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"database_id": {"type": "string", "description": "Database ID"},
|
||||
"collection_id": {"type": "string", "description": "Collection ID"},
|
||||
"limit": {
|
||||
"type": "integer",
|
||||
"description": "Results per page",
|
||||
"default": 25,
|
||||
"maximum": 100,
|
||||
},
|
||||
"cursor": {
|
||||
"anyOf": [{"type": "string"}, {"type": "null"}],
|
||||
"description": "Cursor from previous response for next page",
|
||||
},
|
||||
"cursor_direction": {
|
||||
"type": "string",
|
||||
"enum": ["after", "before"],
|
||||
"description": "Cursor direction",
|
||||
"default": "after",
|
||||
},
|
||||
"order_attribute": {
|
||||
"anyOf": [{"type": "string"}, {"type": "null"}],
|
||||
"description": "Attribute to order by (default: $id)",
|
||||
},
|
||||
"order_type": {
|
||||
"type": "string",
|
||||
"enum": ["ASC", "DESC"],
|
||||
"description": "Sort order",
|
||||
"default": "DESC",
|
||||
},
|
||||
"filters": {
|
||||
"anyOf": [{"type": "array", "items": {"type": "string"}}, {"type": "null"}],
|
||||
"description": "Additional filter queries",
|
||||
},
|
||||
},
|
||||
"required": ["database_id", "collection_id"],
|
||||
},
|
||||
"scope": "read",
|
||||
},
|
||||
]
|
||||
|
||||
# =====================
|
||||
# HANDLER FUNCTIONS
|
||||
# =====================
|
||||
|
||||
async def list_documents(
|
||||
client: AppwriteClient, database_id: str, collection_id: str, queries: list[str] | None = None
|
||||
) -> str:
|
||||
"""List documents with queries."""
|
||||
try:
|
||||
result = await client.list_documents(
|
||||
database_id=database_id, collection_id=collection_id, queries=queries
|
||||
)
|
||||
documents = result.get("documents", [])
|
||||
|
||||
response = {
|
||||
"success": True,
|
||||
"database_id": database_id,
|
||||
"collection_id": collection_id,
|
||||
"total": result.get("total", len(documents)),
|
||||
"documents": documents,
|
||||
}
|
||||
return json.dumps(response, indent=2, ensure_ascii=False)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
|
||||
async def get_document(
|
||||
client: AppwriteClient,
|
||||
database_id: str,
|
||||
collection_id: str,
|
||||
document_id: str,
|
||||
queries: list[str] | None = None,
|
||||
) -> str:
|
||||
"""Get document by ID."""
|
||||
try:
|
||||
result = await client.get_document(
|
||||
database_id=database_id,
|
||||
collection_id=collection_id,
|
||||
document_id=document_id,
|
||||
queries=queries,
|
||||
)
|
||||
return json.dumps({"success": True, "document": result}, indent=2, ensure_ascii=False)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
|
||||
async def create_document(
|
||||
client: AppwriteClient,
|
||||
database_id: str,
|
||||
collection_id: str,
|
||||
document_id: str,
|
||||
data: dict[str, Any],
|
||||
permissions: list[str] | None = None,
|
||||
) -> str:
|
||||
"""Create a new document."""
|
||||
try:
|
||||
result = await client.create_document(
|
||||
database_id=database_id,
|
||||
collection_id=collection_id,
|
||||
document_id=document_id,
|
||||
data=data,
|
||||
permissions=permissions,
|
||||
)
|
||||
return json.dumps(
|
||||
{"success": True, "message": "Document created successfully", "document": result},
|
||||
indent=2,
|
||||
ensure_ascii=False,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
|
||||
async def update_document(
|
||||
client: AppwriteClient,
|
||||
database_id: str,
|
||||
collection_id: str,
|
||||
document_id: str,
|
||||
data: dict[str, Any] | None = None,
|
||||
permissions: list[str] | None = None,
|
||||
) -> str:
|
||||
"""Update document."""
|
||||
try:
|
||||
result = await client.update_document(
|
||||
database_id=database_id,
|
||||
collection_id=collection_id,
|
||||
document_id=document_id,
|
||||
data=data,
|
||||
permissions=permissions,
|
||||
)
|
||||
return json.dumps(
|
||||
{"success": True, "message": "Document updated successfully", "document": result},
|
||||
indent=2,
|
||||
ensure_ascii=False,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
|
||||
async def delete_document(
|
||||
client: AppwriteClient, database_id: str, collection_id: str, document_id: str
|
||||
) -> str:
|
||||
"""Delete document."""
|
||||
try:
|
||||
await client.delete_document(database_id, collection_id, document_id)
|
||||
return json.dumps(
|
||||
{"success": True, "message": f"Document '{document_id}' deleted successfully"}, indent=2
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
|
||||
async def bulk_create_documents(
|
||||
client: AppwriteClient, database_id: str, collection_id: str, documents: list[dict[str, Any]]
|
||||
) -> str:
|
||||
"""Create multiple documents."""
|
||||
try:
|
||||
results = []
|
||||
errors = []
|
||||
|
||||
for doc in documents:
|
||||
try:
|
||||
result = await client.create_document(
|
||||
database_id=database_id,
|
||||
collection_id=collection_id,
|
||||
document_id=doc.get("document_id", "unique()"),
|
||||
data=doc["data"],
|
||||
permissions=doc.get("permissions"),
|
||||
)
|
||||
results.append({"id": result.get("$id"), "success": True})
|
||||
except Exception as e:
|
||||
errors.append({"document_id": doc.get("document_id"), "error": str(e)})
|
||||
|
||||
response = {
|
||||
"success": len(errors) == 0,
|
||||
"created": len(results),
|
||||
"failed": len(errors),
|
||||
"results": results,
|
||||
}
|
||||
if errors:
|
||||
response["errors"] = errors
|
||||
|
||||
return json.dumps(response, indent=2, ensure_ascii=False)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
|
||||
async def bulk_update_documents(
|
||||
client: AppwriteClient, database_id: str, collection_id: str, updates: list[dict[str, Any]]
|
||||
) -> str:
|
||||
"""Update multiple documents."""
|
||||
try:
|
||||
results = []
|
||||
errors = []
|
||||
|
||||
for update in updates:
|
||||
try:
|
||||
result = await client.update_document(
|
||||
database_id=database_id,
|
||||
collection_id=collection_id,
|
||||
document_id=update["document_id"],
|
||||
data=update.get("data"),
|
||||
permissions=update.get("permissions"),
|
||||
)
|
||||
results.append({"id": result.get("$id"), "success": True})
|
||||
except Exception as e:
|
||||
errors.append({"document_id": update["document_id"], "error": str(e)})
|
||||
|
||||
response = {
|
||||
"success": len(errors) == 0,
|
||||
"updated": len(results),
|
||||
"failed": len(errors),
|
||||
"results": results,
|
||||
}
|
||||
if errors:
|
||||
response["errors"] = errors
|
||||
|
||||
return json.dumps(response, indent=2, ensure_ascii=False)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
|
||||
async def bulk_delete_documents(
|
||||
client: AppwriteClient, database_id: str, collection_id: str, document_ids: list[str]
|
||||
) -> str:
|
||||
"""Delete multiple documents."""
|
||||
try:
|
||||
results = []
|
||||
errors = []
|
||||
|
||||
for doc_id in document_ids:
|
||||
try:
|
||||
await client.delete_document(database_id, collection_id, doc_id)
|
||||
results.append({"id": doc_id, "success": True})
|
||||
except Exception as e:
|
||||
errors.append({"document_id": doc_id, "error": str(e)})
|
||||
|
||||
response = {
|
||||
"success": len(errors) == 0,
|
||||
"deleted": len(results),
|
||||
"failed": len(errors),
|
||||
"results": results,
|
||||
}
|
||||
if errors:
|
||||
response["errors"] = errors
|
||||
|
||||
return json.dumps(response, indent=2, ensure_ascii=False)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
|
||||
async def search_documents(
|
||||
client: AppwriteClient,
|
||||
database_id: str,
|
||||
collection_id: str,
|
||||
attribute: str,
|
||||
query: str,
|
||||
limit: int = 25,
|
||||
) -> str:
|
||||
"""Full-text search in documents."""
|
||||
try:
|
||||
# Appwrite 1.7.4 JSON format for queries
|
||||
queries = [_query_search(attribute, query), _query_limit(limit)]
|
||||
result = await client.list_documents(
|
||||
database_id=database_id, collection_id=collection_id, queries=queries
|
||||
)
|
||||
documents = result.get("documents", [])
|
||||
|
||||
response = {
|
||||
"success": True,
|
||||
"query": query,
|
||||
"attribute": attribute,
|
||||
"total": result.get("total", len(documents)),
|
||||
"documents": documents,
|
||||
}
|
||||
return json.dumps(response, indent=2, ensure_ascii=False)
|
||||
|
||||
except Exception as e:
|
||||
error_msg = str(e)
|
||||
if "fulltext" in error_msg.lower() or "index" in error_msg.lower():
|
||||
error_msg += " (Hint: Make sure you have a fulltext index on the searched attribute)"
|
||||
return json.dumps({"success": False, "error": error_msg}, indent=2)
|
||||
|
||||
async def count_documents(
|
||||
client: AppwriteClient, database_id: str, collection_id: str, queries: list[str] | None = None
|
||||
) -> str:
|
||||
"""Count documents in collection."""
|
||||
try:
|
||||
# Build query list: start with user filters, add limit(1) to minimize data
|
||||
count_queries = []
|
||||
|
||||
# Add user-provided filter queries (make a copy to avoid mutating input)
|
||||
if queries and len(queries) > 0:
|
||||
count_queries.extend(queries)
|
||||
|
||||
# Always add limit(1) to minimize data transfer - Appwrite 1.7.4 JSON format
|
||||
count_queries.append(_query_limit(1))
|
||||
|
||||
result = await client.list_documents(
|
||||
database_id=database_id, collection_id=collection_id, queries=count_queries
|
||||
)
|
||||
|
||||
response = {
|
||||
"success": True,
|
||||
"database_id": database_id,
|
||||
"collection_id": collection_id,
|
||||
"count": result.get("total", 0),
|
||||
}
|
||||
return json.dumps(response, indent=2, ensure_ascii=False)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
|
||||
async def get_documents_by_ids(
|
||||
client: AppwriteClient, database_id: str, collection_id: str, document_ids: list[str]
|
||||
) -> str:
|
||||
"""Get multiple documents by IDs."""
|
||||
try:
|
||||
documents = []
|
||||
errors = []
|
||||
|
||||
for doc_id in document_ids:
|
||||
try:
|
||||
doc = await client.get_document(
|
||||
database_id=database_id, collection_id=collection_id, document_id=doc_id
|
||||
)
|
||||
documents.append(doc)
|
||||
except Exception as e:
|
||||
errors.append({"document_id": doc_id, "error": str(e)})
|
||||
|
||||
response = {
|
||||
"success": len(errors) == 0,
|
||||
"found": len(documents),
|
||||
"not_found": len(errors),
|
||||
"documents": documents,
|
||||
}
|
||||
if errors:
|
||||
response["errors"] = errors
|
||||
|
||||
return json.dumps(response, indent=2, ensure_ascii=False)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
|
||||
async def list_documents_paginated(
|
||||
client: AppwriteClient,
|
||||
database_id: str,
|
||||
collection_id: str,
|
||||
limit: int = 25,
|
||||
cursor: str | None = None,
|
||||
cursor_direction: str = "after",
|
||||
order_attribute: str | None = None,
|
||||
order_type: str = "DESC",
|
||||
filters: list[str] | None = None,
|
||||
) -> str:
|
||||
"""List documents with cursor pagination."""
|
||||
try:
|
||||
# Build query list (don't mutate input) - Appwrite 1.7.4 JSON format
|
||||
queries = []
|
||||
|
||||
# Add user-provided filter queries
|
||||
if filters and len(filters) > 0:
|
||||
queries.extend(filters)
|
||||
|
||||
# Add ordering only if explicitly specified
|
||||
if order_attribute:
|
||||
if order_type == "DESC":
|
||||
queries.append(_query_order_desc(order_attribute))
|
||||
else:
|
||||
queries.append(_query_order_asc(order_attribute))
|
||||
|
||||
# Add cursor
|
||||
if cursor:
|
||||
if cursor_direction == "after":
|
||||
queries.append(_query_cursor_after(cursor))
|
||||
else:
|
||||
queries.append(_query_cursor_before(cursor))
|
||||
|
||||
# Add limit only if queries exist or limit differs from default
|
||||
if queries or limit != 25:
|
||||
queries.append(_query_limit(min(limit, 100)))
|
||||
|
||||
result = await client.list_documents(
|
||||
database_id=database_id,
|
||||
collection_id=collection_id,
|
||||
queries=queries if queries else None,
|
||||
)
|
||||
documents = result.get("documents", [])
|
||||
|
||||
# Determine next cursor
|
||||
next_cursor = None
|
||||
if documents and len(documents) == limit:
|
||||
next_cursor = documents[-1].get("$id")
|
||||
|
||||
response = {
|
||||
"success": True,
|
||||
"total": result.get("total", 0),
|
||||
"count": len(documents),
|
||||
"documents": documents,
|
||||
"pagination": {
|
||||
"limit": limit,
|
||||
"cursor": cursor,
|
||||
"next_cursor": next_cursor,
|
||||
"has_more": next_cursor is not None,
|
||||
},
|
||||
}
|
||||
return json.dumps(response, indent=2, ensure_ascii=False)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
Reference in New Issue
Block a user