diff --git a/pyproject.toml b/pyproject.toml index df52f71..6de95ad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -72,3 +72,16 @@ build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] packages = ["robosystems_client"] +[tool.basedpyright] +include = [] +exclude = ["**/*"] +extraPaths = ["."] +pythonVersion = "3.12" +venvPath = "." +venv = ".venv" +typeCheckingMode = "standard" +reportAttributeAccessIssue = "none" +reportArgumentType = "none" +reportGeneralTypeIssues = "none" +reportOptionalMemberAccess = "none" +reportReturnType = "none" diff --git a/robosystems_client/api/query/execute_cypher_query.py b/robosystems_client/api/query/execute_cypher_query.py index 25d2e29..c34a26d 100644 --- a/robosystems_client/api/query/execute_cypher_query.py +++ b/robosystems_client/api/query/execute_cypher_query.py @@ -67,11 +67,6 @@ def _parse_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response ) -> Optional[Union[Any, HTTPValidationError]]: if response.status_code == 200: - # Check if this is NDJSON - if so, skip parsing (will be handled by client) - content_type = response.headers.get("content-type", "") - stream_format = response.headers.get("x-stream-format", "") - if "application/x-ndjson" in content_type or stream_format == "ndjson": - return None # Skip parsing, client will handle NDJSON response_200 = response.json() return response_200 diff --git a/robosystems_client/api/tables/delete_file.py b/robosystems_client/api/tables/delete_file.py new file mode 100644 index 0000000..408f86a --- /dev/null +++ b/robosystems_client/api/tables/delete_file.py @@ -0,0 +1,437 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.delete_file_response import DeleteFileResponse +from ...models.error_response import ErrorResponse +from ...models.http_validation_error import HTTPValidationError +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + graph_id: str, + file_id: str, + *, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + if not isinstance(authorization, Unset): + headers["authorization"] = authorization + + params: dict[str, Any] = {} + + json_token: Union[None, Unset, str] + if isinstance(token, Unset): + json_token = UNSET + else: + json_token = token + params["token"] = json_token + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": f"/v1/graphs/{graph_id}/tables/files/{file_id}", + "params": params, + } + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, DeleteFileResponse, ErrorResponse, HTTPValidationError]]: + if response.status_code == 200: + response_200 = DeleteFileResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = ErrorResponse.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ErrorResponse.from_dict(response.json()) + + return response_404 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if response.status_code == 500: + response_500 = cast(Any, None) + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, DeleteFileResponse, ErrorResponse, HTTPValidationError]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + graph_id: str, + file_id: str, + *, + client: AuthenticatedClient, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Response[Union[Any, DeleteFileResponse, ErrorResponse, HTTPValidationError]]: + r""" Delete File from Staging + + Delete a file from S3 storage and database tracking. + + **Purpose:** + Remove unwanted, duplicate, or incorrect files from staging tables before ingestion. + The file is deleted from both S3 and database tracking, and table statistics + are automatically recalculated. + + **Use Cases:** + - Remove duplicate uploads + - Delete files with incorrect data + - Clean up failed uploads + - Fix data quality issues before ingestion + - Manage storage usage + + **What Happens:** + 1. File deleted from S3 storage + 2. Database tracking record removed + 3. Table statistics recalculated (file count, size, row count) + 4. DuckDB automatically excludes file from future queries + + **Security:** + - Write access required (verified via auth) + - Shared repositories block file deletions + - Full audit trail of deletion operations + - Cannot delete after ingestion to graph + + **Example Response:** + ```json + { + \"status\": \"deleted\", + \"file_id\": \"f123\", + \"file_name\": \"entities_batch1.parquet\", + \"message\": \"File deleted successfully. DuckDB will automatically exclude it from queries.\" + } + ``` + + **Example Usage:** + ```bash + curl -X DELETE -H \"Authorization: Bearer YOUR_TOKEN\" \ + https://api.robosystems.ai/v1/graphs/kg123/tables/files/f123 + ``` + + **Tips:** + - Delete files before ingestion for best results + - Table statistics update automatically + - No need to refresh DuckDB - exclusion is automatic + - Consider re-uploading corrected version after deletion + + **Note:** + File deletion is included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + file_id (str): File ID + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, DeleteFileResponse, ErrorResponse, HTTPValidationError]] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + file_id=file_id, + token=token, + authorization=authorization, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + graph_id: str, + file_id: str, + *, + client: AuthenticatedClient, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Optional[Union[Any, DeleteFileResponse, ErrorResponse, HTTPValidationError]]: + r""" Delete File from Staging + + Delete a file from S3 storage and database tracking. + + **Purpose:** + Remove unwanted, duplicate, or incorrect files from staging tables before ingestion. + The file is deleted from both S3 and database tracking, and table statistics + are automatically recalculated. + + **Use Cases:** + - Remove duplicate uploads + - Delete files with incorrect data + - Clean up failed uploads + - Fix data quality issues before ingestion + - Manage storage usage + + **What Happens:** + 1. File deleted from S3 storage + 2. Database tracking record removed + 3. Table statistics recalculated (file count, size, row count) + 4. DuckDB automatically excludes file from future queries + + **Security:** + - Write access required (verified via auth) + - Shared repositories block file deletions + - Full audit trail of deletion operations + - Cannot delete after ingestion to graph + + **Example Response:** + ```json + { + \"status\": \"deleted\", + \"file_id\": \"f123\", + \"file_name\": \"entities_batch1.parquet\", + \"message\": \"File deleted successfully. DuckDB will automatically exclude it from queries.\" + } + ``` + + **Example Usage:** + ```bash + curl -X DELETE -H \"Authorization: Bearer YOUR_TOKEN\" \ + https://api.robosystems.ai/v1/graphs/kg123/tables/files/f123 + ``` + + **Tips:** + - Delete files before ingestion for best results + - Table statistics update automatically + - No need to refresh DuckDB - exclusion is automatic + - Consider re-uploading corrected version after deletion + + **Note:** + File deletion is included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + file_id (str): File ID + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, DeleteFileResponse, ErrorResponse, HTTPValidationError] + """ + + return sync_detailed( + graph_id=graph_id, + file_id=file_id, + client=client, + token=token, + authorization=authorization, + ).parsed + + +async def asyncio_detailed( + graph_id: str, + file_id: str, + *, + client: AuthenticatedClient, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Response[Union[Any, DeleteFileResponse, ErrorResponse, HTTPValidationError]]: + r""" Delete File from Staging + + Delete a file from S3 storage and database tracking. + + **Purpose:** + Remove unwanted, duplicate, or incorrect files from staging tables before ingestion. + The file is deleted from both S3 and database tracking, and table statistics + are automatically recalculated. + + **Use Cases:** + - Remove duplicate uploads + - Delete files with incorrect data + - Clean up failed uploads + - Fix data quality issues before ingestion + - Manage storage usage + + **What Happens:** + 1. File deleted from S3 storage + 2. Database tracking record removed + 3. Table statistics recalculated (file count, size, row count) + 4. DuckDB automatically excludes file from future queries + + **Security:** + - Write access required (verified via auth) + - Shared repositories block file deletions + - Full audit trail of deletion operations + - Cannot delete after ingestion to graph + + **Example Response:** + ```json + { + \"status\": \"deleted\", + \"file_id\": \"f123\", + \"file_name\": \"entities_batch1.parquet\", + \"message\": \"File deleted successfully. DuckDB will automatically exclude it from queries.\" + } + ``` + + **Example Usage:** + ```bash + curl -X DELETE -H \"Authorization: Bearer YOUR_TOKEN\" \ + https://api.robosystems.ai/v1/graphs/kg123/tables/files/f123 + ``` + + **Tips:** + - Delete files before ingestion for best results + - Table statistics update automatically + - No need to refresh DuckDB - exclusion is automatic + - Consider re-uploading corrected version after deletion + + **Note:** + File deletion is included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + file_id (str): File ID + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, DeleteFileResponse, ErrorResponse, HTTPValidationError]] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + file_id=file_id, + token=token, + authorization=authorization, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + graph_id: str, + file_id: str, + *, + client: AuthenticatedClient, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Optional[Union[Any, DeleteFileResponse, ErrorResponse, HTTPValidationError]]: + r""" Delete File from Staging + + Delete a file from S3 storage and database tracking. + + **Purpose:** + Remove unwanted, duplicate, or incorrect files from staging tables before ingestion. + The file is deleted from both S3 and database tracking, and table statistics + are automatically recalculated. + + **Use Cases:** + - Remove duplicate uploads + - Delete files with incorrect data + - Clean up failed uploads + - Fix data quality issues before ingestion + - Manage storage usage + + **What Happens:** + 1. File deleted from S3 storage + 2. Database tracking record removed + 3. Table statistics recalculated (file count, size, row count) + 4. DuckDB automatically excludes file from future queries + + **Security:** + - Write access required (verified via auth) + - Shared repositories block file deletions + - Full audit trail of deletion operations + - Cannot delete after ingestion to graph + + **Example Response:** + ```json + { + \"status\": \"deleted\", + \"file_id\": \"f123\", + \"file_name\": \"entities_batch1.parquet\", + \"message\": \"File deleted successfully. DuckDB will automatically exclude it from queries.\" + } + ``` + + **Example Usage:** + ```bash + curl -X DELETE -H \"Authorization: Bearer YOUR_TOKEN\" \ + https://api.robosystems.ai/v1/graphs/kg123/tables/files/f123 + ``` + + **Tips:** + - Delete files before ingestion for best results + - Table statistics update automatically + - No need to refresh DuckDB - exclusion is automatic + - Consider re-uploading corrected version after deletion + + **Note:** + File deletion is included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + file_id (str): File ID + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, DeleteFileResponse, ErrorResponse, HTTPValidationError] + """ + + return ( + await asyncio_detailed( + graph_id=graph_id, + file_id=file_id, + client=client, + token=token, + authorization=authorization, + ) + ).parsed diff --git a/robosystems_client/api/tables/delete_file_v1_graphs_graph_id_tables_files_file_id_delete.py b/robosystems_client/api/tables/delete_file_v1_graphs_graph_id_tables_files_file_id_delete.py deleted file mode 100644 index 7fe4185..0000000 --- a/robosystems_client/api/tables/delete_file_v1_graphs_graph_id_tables_files_file_id_delete.py +++ /dev/null @@ -1,287 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union, cast - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.delete_file_v1_graphs_graph_id_tables_files_file_id_delete_response_delete_file_v1_graphs_graph_id_tables_files_file_id_delete import ( - DeleteFileV1GraphsGraphIdTablesFilesFileIdDeleteResponseDeleteFileV1GraphsGraphIdTablesFilesFileIdDelete, -) -from ...models.error_response import ErrorResponse -from ...models.http_validation_error import HTTPValidationError -from ...types import UNSET, Response, Unset - - -def _get_kwargs( - graph_id: str, - file_id: str, - *, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - if not isinstance(authorization, Unset): - headers["authorization"] = authorization - - params: dict[str, Any] = {} - - json_token: Union[None, Unset, str] - if isinstance(token, Unset): - json_token = UNSET - else: - json_token = token - params["token"] = json_token - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "delete", - "url": f"/v1/graphs/{graph_id}/tables/files/{file_id}", - "params": params, - } - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[ - Union[ - Any, - DeleteFileV1GraphsGraphIdTablesFilesFileIdDeleteResponseDeleteFileV1GraphsGraphIdTablesFilesFileIdDelete, - ErrorResponse, - HTTPValidationError, - ] -]: - if response.status_code == 200: - response_200 = DeleteFileV1GraphsGraphIdTablesFilesFileIdDeleteResponseDeleteFileV1GraphsGraphIdTablesFilesFileIdDelete.from_dict( - response.json() - ) - - return response_200 - - if response.status_code == 401: - response_401 = cast(Any, None) - return response_401 - - if response.status_code == 403: - response_403 = ErrorResponse.from_dict(response.json()) - - return response_403 - - if response.status_code == 404: - response_404 = ErrorResponse.from_dict(response.json()) - - return response_404 - - if response.status_code == 422: - response_422 = HTTPValidationError.from_dict(response.json()) - - return response_422 - - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[ - Union[ - Any, - DeleteFileV1GraphsGraphIdTablesFilesFileIdDeleteResponseDeleteFileV1GraphsGraphIdTablesFilesFileIdDelete, - ErrorResponse, - HTTPValidationError, - ] -]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - graph_id: str, - file_id: str, - *, - client: AuthenticatedClient, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Response[ - Union[ - Any, - DeleteFileV1GraphsGraphIdTablesFilesFileIdDeleteResponseDeleteFileV1GraphsGraphIdTablesFilesFileIdDelete, - ErrorResponse, - HTTPValidationError, - ] -]: - """Delete File - - Delete a specific file from S3 and database tracking. DuckDB will automatically exclude it from - queries. - - Args: - graph_id (str): Graph database identifier - file_id (str): File ID - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, DeleteFileV1GraphsGraphIdTablesFilesFileIdDeleteResponseDeleteFileV1GraphsGraphIdTablesFilesFileIdDelete, ErrorResponse, HTTPValidationError]] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - file_id=file_id, - token=token, - authorization=authorization, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - graph_id: str, - file_id: str, - *, - client: AuthenticatedClient, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Optional[ - Union[ - Any, - DeleteFileV1GraphsGraphIdTablesFilesFileIdDeleteResponseDeleteFileV1GraphsGraphIdTablesFilesFileIdDelete, - ErrorResponse, - HTTPValidationError, - ] -]: - """Delete File - - Delete a specific file from S3 and database tracking. DuckDB will automatically exclude it from - queries. - - Args: - graph_id (str): Graph database identifier - file_id (str): File ID - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, DeleteFileV1GraphsGraphIdTablesFilesFileIdDeleteResponseDeleteFileV1GraphsGraphIdTablesFilesFileIdDelete, ErrorResponse, HTTPValidationError] - """ - - return sync_detailed( - graph_id=graph_id, - file_id=file_id, - client=client, - token=token, - authorization=authorization, - ).parsed - - -async def asyncio_detailed( - graph_id: str, - file_id: str, - *, - client: AuthenticatedClient, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Response[ - Union[ - Any, - DeleteFileV1GraphsGraphIdTablesFilesFileIdDeleteResponseDeleteFileV1GraphsGraphIdTablesFilesFileIdDelete, - ErrorResponse, - HTTPValidationError, - ] -]: - """Delete File - - Delete a specific file from S3 and database tracking. DuckDB will automatically exclude it from - queries. - - Args: - graph_id (str): Graph database identifier - file_id (str): File ID - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, DeleteFileV1GraphsGraphIdTablesFilesFileIdDeleteResponseDeleteFileV1GraphsGraphIdTablesFilesFileIdDelete, ErrorResponse, HTTPValidationError]] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - file_id=file_id, - token=token, - authorization=authorization, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - graph_id: str, - file_id: str, - *, - client: AuthenticatedClient, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Optional[ - Union[ - Any, - DeleteFileV1GraphsGraphIdTablesFilesFileIdDeleteResponseDeleteFileV1GraphsGraphIdTablesFilesFileIdDelete, - ErrorResponse, - HTTPValidationError, - ] -]: - """Delete File - - Delete a specific file from S3 and database tracking. DuckDB will automatically exclude it from - queries. - - Args: - graph_id (str): Graph database identifier - file_id (str): File ID - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, DeleteFileV1GraphsGraphIdTablesFilesFileIdDeleteResponseDeleteFileV1GraphsGraphIdTablesFilesFileIdDelete, ErrorResponse, HTTPValidationError] - """ - - return ( - await asyncio_detailed( - graph_id=graph_id, - file_id=file_id, - client=client, - token=token, - authorization=authorization, - ) - ).parsed diff --git a/robosystems_client/api/tables/get_file_info.py b/robosystems_client/api/tables/get_file_info.py new file mode 100644 index 0000000..557134f --- /dev/null +++ b/robosystems_client/api/tables/get_file_info.py @@ -0,0 +1,397 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error_response import ErrorResponse +from ...models.get_file_info_response import GetFileInfoResponse +from ...models.http_validation_error import HTTPValidationError +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + graph_id: str, + file_id: str, + *, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + if not isinstance(authorization, Unset): + headers["authorization"] = authorization + + params: dict[str, Any] = {} + + json_token: Union[None, Unset, str] + if isinstance(token, Unset): + json_token = UNSET + else: + json_token = token + params["token"] = json_token + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/v1/graphs/{graph_id}/tables/files/{file_id}", + "params": params, + } + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, ErrorResponse, GetFileInfoResponse, HTTPValidationError]]: + if response.status_code == 200: + response_200 = GetFileInfoResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = ErrorResponse.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ErrorResponse.from_dict(response.json()) + + return response_404 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, ErrorResponse, GetFileInfoResponse, HTTPValidationError]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + graph_id: str, + file_id: str, + *, + client: AuthenticatedClient, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Response[Union[Any, ErrorResponse, GetFileInfoResponse, HTTPValidationError]]: + r""" Get File Information + + Get detailed information about a specific file. + + **Purpose:** + Retrieve comprehensive metadata for a single file, including upload status, + size, row count, and timestamps. Useful for validating individual files + before ingestion. + + **Use Cases:** + - Validate file upload completion + - Check file metadata before ingestion + - Debug upload issues + - Verify file format and size + - Track file lifecycle + + **Example Response:** + ```json + { + \"file_id\": \"f123\", + \"graph_id\": \"kg123\", + \"table_id\": \"t456\", + \"table_name\": \"Entity\", + \"file_name\": \"entities_batch1.parquet\", + \"file_format\": \"parquet\", + \"size_bytes\": 1048576, + \"row_count\": 5000, + \"upload_status\": \"uploaded\", + \"upload_method\": \"presigned_url\", + \"created_at\": \"2025-10-28T10:00:00Z\", + \"uploaded_at\": \"2025-10-28T10:01:30Z\", + \"s3_key\": \"user-staging/user123/kg123/Entity/entities_batch1.parquet\" + } + ``` + + **Example Usage:** + ```bash + curl -H \"Authorization: Bearer YOUR_TOKEN\" \ + https://api.robosystems.ai/v1/graphs/kg123/tables/files/f123 + ``` + + **Note:** + File info retrieval is included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + file_id (str): File ID + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, ErrorResponse, GetFileInfoResponse, HTTPValidationError]] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + file_id=file_id, + token=token, + authorization=authorization, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + graph_id: str, + file_id: str, + *, + client: AuthenticatedClient, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Optional[Union[Any, ErrorResponse, GetFileInfoResponse, HTTPValidationError]]: + r""" Get File Information + + Get detailed information about a specific file. + + **Purpose:** + Retrieve comprehensive metadata for a single file, including upload status, + size, row count, and timestamps. Useful for validating individual files + before ingestion. + + **Use Cases:** + - Validate file upload completion + - Check file metadata before ingestion + - Debug upload issues + - Verify file format and size + - Track file lifecycle + + **Example Response:** + ```json + { + \"file_id\": \"f123\", + \"graph_id\": \"kg123\", + \"table_id\": \"t456\", + \"table_name\": \"Entity\", + \"file_name\": \"entities_batch1.parquet\", + \"file_format\": \"parquet\", + \"size_bytes\": 1048576, + \"row_count\": 5000, + \"upload_status\": \"uploaded\", + \"upload_method\": \"presigned_url\", + \"created_at\": \"2025-10-28T10:00:00Z\", + \"uploaded_at\": \"2025-10-28T10:01:30Z\", + \"s3_key\": \"user-staging/user123/kg123/Entity/entities_batch1.parquet\" + } + ``` + + **Example Usage:** + ```bash + curl -H \"Authorization: Bearer YOUR_TOKEN\" \ + https://api.robosystems.ai/v1/graphs/kg123/tables/files/f123 + ``` + + **Note:** + File info retrieval is included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + file_id (str): File ID + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, ErrorResponse, GetFileInfoResponse, HTTPValidationError] + """ + + return sync_detailed( + graph_id=graph_id, + file_id=file_id, + client=client, + token=token, + authorization=authorization, + ).parsed + + +async def asyncio_detailed( + graph_id: str, + file_id: str, + *, + client: AuthenticatedClient, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Response[Union[Any, ErrorResponse, GetFileInfoResponse, HTTPValidationError]]: + r""" Get File Information + + Get detailed information about a specific file. + + **Purpose:** + Retrieve comprehensive metadata for a single file, including upload status, + size, row count, and timestamps. Useful for validating individual files + before ingestion. + + **Use Cases:** + - Validate file upload completion + - Check file metadata before ingestion + - Debug upload issues + - Verify file format and size + - Track file lifecycle + + **Example Response:** + ```json + { + \"file_id\": \"f123\", + \"graph_id\": \"kg123\", + \"table_id\": \"t456\", + \"table_name\": \"Entity\", + \"file_name\": \"entities_batch1.parquet\", + \"file_format\": \"parquet\", + \"size_bytes\": 1048576, + \"row_count\": 5000, + \"upload_status\": \"uploaded\", + \"upload_method\": \"presigned_url\", + \"created_at\": \"2025-10-28T10:00:00Z\", + \"uploaded_at\": \"2025-10-28T10:01:30Z\", + \"s3_key\": \"user-staging/user123/kg123/Entity/entities_batch1.parquet\" + } + ``` + + **Example Usage:** + ```bash + curl -H \"Authorization: Bearer YOUR_TOKEN\" \ + https://api.robosystems.ai/v1/graphs/kg123/tables/files/f123 + ``` + + **Note:** + File info retrieval is included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + file_id (str): File ID + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, ErrorResponse, GetFileInfoResponse, HTTPValidationError]] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + file_id=file_id, + token=token, + authorization=authorization, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + graph_id: str, + file_id: str, + *, + client: AuthenticatedClient, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Optional[Union[Any, ErrorResponse, GetFileInfoResponse, HTTPValidationError]]: + r""" Get File Information + + Get detailed information about a specific file. + + **Purpose:** + Retrieve comprehensive metadata for a single file, including upload status, + size, row count, and timestamps. Useful for validating individual files + before ingestion. + + **Use Cases:** + - Validate file upload completion + - Check file metadata before ingestion + - Debug upload issues + - Verify file format and size + - Track file lifecycle + + **Example Response:** + ```json + { + \"file_id\": \"f123\", + \"graph_id\": \"kg123\", + \"table_id\": \"t456\", + \"table_name\": \"Entity\", + \"file_name\": \"entities_batch1.parquet\", + \"file_format\": \"parquet\", + \"size_bytes\": 1048576, + \"row_count\": 5000, + \"upload_status\": \"uploaded\", + \"upload_method\": \"presigned_url\", + \"created_at\": \"2025-10-28T10:00:00Z\", + \"uploaded_at\": \"2025-10-28T10:01:30Z\", + \"s3_key\": \"user-staging/user123/kg123/Entity/entities_batch1.parquet\" + } + ``` + + **Example Usage:** + ```bash + curl -H \"Authorization: Bearer YOUR_TOKEN\" \ + https://api.robosystems.ai/v1/graphs/kg123/tables/files/f123 + ``` + + **Note:** + File info retrieval is included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + file_id (str): File ID + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, ErrorResponse, GetFileInfoResponse, HTTPValidationError] + """ + + return ( + await asyncio_detailed( + graph_id=graph_id, + file_id=file_id, + client=client, + token=token, + authorization=authorization, + ) + ).parsed diff --git a/robosystems_client/api/tables/get_file_info_v1_graphs_graph_id_tables_files_file_id_get.py b/robosystems_client/api/tables/get_file_info_v1_graphs_graph_id_tables_files_file_id_get.py deleted file mode 100644 index 6026711..0000000 --- a/robosystems_client/api/tables/get_file_info_v1_graphs_graph_id_tables_files_file_id_get.py +++ /dev/null @@ -1,283 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union, cast - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.error_response import ErrorResponse -from ...models.get_file_info_v1_graphs_graph_id_tables_files_file_id_get_response_get_file_info_v1_graphs_graph_id_tables_files_file_id_get import ( - GetFileInfoV1GraphsGraphIdTablesFilesFileIdGetResponseGetFileInfoV1GraphsGraphIdTablesFilesFileIdGet, -) -from ...models.http_validation_error import HTTPValidationError -from ...types import UNSET, Response, Unset - - -def _get_kwargs( - graph_id: str, - file_id: str, - *, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - if not isinstance(authorization, Unset): - headers["authorization"] = authorization - - params: dict[str, Any] = {} - - json_token: Union[None, Unset, str] - if isinstance(token, Unset): - json_token = UNSET - else: - json_token = token - params["token"] = json_token - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "get", - "url": f"/v1/graphs/{graph_id}/tables/files/{file_id}", - "params": params, - } - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[ - Union[ - Any, - ErrorResponse, - GetFileInfoV1GraphsGraphIdTablesFilesFileIdGetResponseGetFileInfoV1GraphsGraphIdTablesFilesFileIdGet, - HTTPValidationError, - ] -]: - if response.status_code == 200: - response_200 = GetFileInfoV1GraphsGraphIdTablesFilesFileIdGetResponseGetFileInfoV1GraphsGraphIdTablesFilesFileIdGet.from_dict( - response.json() - ) - - return response_200 - - if response.status_code == 401: - response_401 = cast(Any, None) - return response_401 - - if response.status_code == 403: - response_403 = ErrorResponse.from_dict(response.json()) - - return response_403 - - if response.status_code == 404: - response_404 = ErrorResponse.from_dict(response.json()) - - return response_404 - - if response.status_code == 422: - response_422 = HTTPValidationError.from_dict(response.json()) - - return response_422 - - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[ - Union[ - Any, - ErrorResponse, - GetFileInfoV1GraphsGraphIdTablesFilesFileIdGetResponseGetFileInfoV1GraphsGraphIdTablesFilesFileIdGet, - HTTPValidationError, - ] -]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - graph_id: str, - file_id: str, - *, - client: AuthenticatedClient, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Response[ - Union[ - Any, - ErrorResponse, - GetFileInfoV1GraphsGraphIdTablesFilesFileIdGetResponseGetFileInfoV1GraphsGraphIdTablesFilesFileIdGet, - HTTPValidationError, - ] -]: - """Get File Info - - Get detailed information about a specific file - - Args: - graph_id (str): Graph database identifier - file_id (str): File ID - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, ErrorResponse, GetFileInfoV1GraphsGraphIdTablesFilesFileIdGetResponseGetFileInfoV1GraphsGraphIdTablesFilesFileIdGet, HTTPValidationError]] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - file_id=file_id, - token=token, - authorization=authorization, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - graph_id: str, - file_id: str, - *, - client: AuthenticatedClient, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Optional[ - Union[ - Any, - ErrorResponse, - GetFileInfoV1GraphsGraphIdTablesFilesFileIdGetResponseGetFileInfoV1GraphsGraphIdTablesFilesFileIdGet, - HTTPValidationError, - ] -]: - """Get File Info - - Get detailed information about a specific file - - Args: - graph_id (str): Graph database identifier - file_id (str): File ID - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, ErrorResponse, GetFileInfoV1GraphsGraphIdTablesFilesFileIdGetResponseGetFileInfoV1GraphsGraphIdTablesFilesFileIdGet, HTTPValidationError] - """ - - return sync_detailed( - graph_id=graph_id, - file_id=file_id, - client=client, - token=token, - authorization=authorization, - ).parsed - - -async def asyncio_detailed( - graph_id: str, - file_id: str, - *, - client: AuthenticatedClient, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Response[ - Union[ - Any, - ErrorResponse, - GetFileInfoV1GraphsGraphIdTablesFilesFileIdGetResponseGetFileInfoV1GraphsGraphIdTablesFilesFileIdGet, - HTTPValidationError, - ] -]: - """Get File Info - - Get detailed information about a specific file - - Args: - graph_id (str): Graph database identifier - file_id (str): File ID - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, ErrorResponse, GetFileInfoV1GraphsGraphIdTablesFilesFileIdGetResponseGetFileInfoV1GraphsGraphIdTablesFilesFileIdGet, HTTPValidationError]] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - file_id=file_id, - token=token, - authorization=authorization, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - graph_id: str, - file_id: str, - *, - client: AuthenticatedClient, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Optional[ - Union[ - Any, - ErrorResponse, - GetFileInfoV1GraphsGraphIdTablesFilesFileIdGetResponseGetFileInfoV1GraphsGraphIdTablesFilesFileIdGet, - HTTPValidationError, - ] -]: - """Get File Info - - Get detailed information about a specific file - - Args: - graph_id (str): Graph database identifier - file_id (str): File ID - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, ErrorResponse, GetFileInfoV1GraphsGraphIdTablesFilesFileIdGetResponseGetFileInfoV1GraphsGraphIdTablesFilesFileIdGet, HTTPValidationError] - """ - - return ( - await asyncio_detailed( - graph_id=graph_id, - file_id=file_id, - client=client, - token=token, - authorization=authorization, - ) - ).parsed diff --git a/robosystems_client/api/tables/get_upload_url.py b/robosystems_client/api/tables/get_upload_url.py new file mode 100644 index 0000000..c778acb --- /dev/null +++ b/robosystems_client/api/tables/get_upload_url.py @@ -0,0 +1,548 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error_response import ErrorResponse +from ...models.file_upload_request import FileUploadRequest +from ...models.file_upload_response import FileUploadResponse +from ...models.http_validation_error import HTTPValidationError +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + graph_id: str, + table_name: str, + *, + body: FileUploadRequest, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + if not isinstance(authorization, Unset): + headers["authorization"] = authorization + + params: dict[str, Any] = {} + + json_token: Union[None, Unset, str] + if isinstance(token, Unset): + json_token = UNSET + else: + json_token = token + params["token"] = json_token + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": f"/v1/graphs/{graph_id}/tables/{table_name}/files", + "params": params, + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, ErrorResponse, FileUploadResponse, HTTPValidationError]]: + if response.status_code == 200: + response_200 = FileUploadResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = ErrorResponse.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ErrorResponse.from_dict(response.json()) + + return response_404 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if response.status_code == 500: + response_500 = cast(Any, None) + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, ErrorResponse, FileUploadResponse, HTTPValidationError]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + graph_id: str, + table_name: str, + *, + client: AuthenticatedClient, + body: FileUploadRequest, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Response[Union[Any, ErrorResponse, FileUploadResponse, HTTPValidationError]]: + r""" Get File Upload URL + + Generate a presigned S3 URL for secure file upload. + + **Purpose:** + Initiate file upload to a staging table by generating a secure, time-limited + presigned S3 URL. Files are uploaded directly to S3, bypassing the API for + optimal performance. + + **Upload Workflow:** + 1. Call this endpoint to get presigned URL + 2. PUT file directly to S3 URL (using curl, axios, etc.) + 3. Call PATCH /tables/files/{file_id} with status='uploaded' + 4. Backend validates file and calculates metrics + 5. File ready for ingestion + + **Supported Formats:** + - Parquet (`application/x-parquet` with `.parquet` extension) + - CSV (`text/csv` with `.csv` extension) + - JSON (`application/json` with `.json` extension) + + **Validation:** + - File extension must match content type + - File name 1-255 characters + - No path traversal characters (.. / \) + - Auto-creates table if it doesn't exist + + **Auto-Table Creation:** + If the table doesn't exist, it's automatically created with: + - Type inferred from name (e.g., \"Transaction\" → relationship) + - Empty schema (populated on ingestion) + - Ready for file uploads + + **Example Response:** + ```json + { + \"upload_url\": \"https://bucket.s3.amazonaws.com/path?X-Amz-Algorithm=...\", + \"expires_in\": 3600, + \"file_id\": \"f123-456-789\", + \"s3_key\": \"user-staging/user123/kg456/Entity/f123.../data.parquet\" + } + ``` + + **Example Usage:** + ```bash + # Step 1: Get upload URL + curl -X POST \"https://api.robosystems.ai/v1/graphs/kg123/tables/Entity/files\" \ + -H \"Authorization: Bearer YOUR_TOKEN\" \ + -H \"Content-Type: application/json\" \ + -d '{ + \"file_name\": \"entities.parquet\", + \"content_type\": \"application/x-parquet\" + }' + + # Step 2: Upload file directly to S3 + curl -X PUT \"$UPLOAD_URL\" \ + -H \"Content-Type: application/x-parquet\" \ + --data-binary \"@entities.parquet\" + + # Step 3: Mark as uploaded + curl -X PATCH \"https://api.robosystems.ai/v1/graphs/kg123/tables/files/$FILE_ID\" \ + -H \"Authorization: Bearer YOUR_TOKEN\" \ + -H \"Content-Type: application/json\" \ + -d '{\"status\": \"uploaded\"}' + ``` + + **Tips:** + - Presigned URLs expire (default: 1 hour) + - Use appropriate Content-Type header when uploading to S3 + - File extension must match content type + - Large files benefit from direct S3 upload + + **Note:** + Upload URL generation is included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + table_name (str): Table name + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + body (FileUploadRequest): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, ErrorResponse, FileUploadResponse, HTTPValidationError]] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + table_name=table_name, + body=body, + token=token, + authorization=authorization, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + graph_id: str, + table_name: str, + *, + client: AuthenticatedClient, + body: FileUploadRequest, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Optional[Union[Any, ErrorResponse, FileUploadResponse, HTTPValidationError]]: + r""" Get File Upload URL + + Generate a presigned S3 URL for secure file upload. + + **Purpose:** + Initiate file upload to a staging table by generating a secure, time-limited + presigned S3 URL. Files are uploaded directly to S3, bypassing the API for + optimal performance. + + **Upload Workflow:** + 1. Call this endpoint to get presigned URL + 2. PUT file directly to S3 URL (using curl, axios, etc.) + 3. Call PATCH /tables/files/{file_id} with status='uploaded' + 4. Backend validates file and calculates metrics + 5. File ready for ingestion + + **Supported Formats:** + - Parquet (`application/x-parquet` with `.parquet` extension) + - CSV (`text/csv` with `.csv` extension) + - JSON (`application/json` with `.json` extension) + + **Validation:** + - File extension must match content type + - File name 1-255 characters + - No path traversal characters (.. / \) + - Auto-creates table if it doesn't exist + + **Auto-Table Creation:** + If the table doesn't exist, it's automatically created with: + - Type inferred from name (e.g., \"Transaction\" → relationship) + - Empty schema (populated on ingestion) + - Ready for file uploads + + **Example Response:** + ```json + { + \"upload_url\": \"https://bucket.s3.amazonaws.com/path?X-Amz-Algorithm=...\", + \"expires_in\": 3600, + \"file_id\": \"f123-456-789\", + \"s3_key\": \"user-staging/user123/kg456/Entity/f123.../data.parquet\" + } + ``` + + **Example Usage:** + ```bash + # Step 1: Get upload URL + curl -X POST \"https://api.robosystems.ai/v1/graphs/kg123/tables/Entity/files\" \ + -H \"Authorization: Bearer YOUR_TOKEN\" \ + -H \"Content-Type: application/json\" \ + -d '{ + \"file_name\": \"entities.parquet\", + \"content_type\": \"application/x-parquet\" + }' + + # Step 2: Upload file directly to S3 + curl -X PUT \"$UPLOAD_URL\" \ + -H \"Content-Type: application/x-parquet\" \ + --data-binary \"@entities.parquet\" + + # Step 3: Mark as uploaded + curl -X PATCH \"https://api.robosystems.ai/v1/graphs/kg123/tables/files/$FILE_ID\" \ + -H \"Authorization: Bearer YOUR_TOKEN\" \ + -H \"Content-Type: application/json\" \ + -d '{\"status\": \"uploaded\"}' + ``` + + **Tips:** + - Presigned URLs expire (default: 1 hour) + - Use appropriate Content-Type header when uploading to S3 + - File extension must match content type + - Large files benefit from direct S3 upload + + **Note:** + Upload URL generation is included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + table_name (str): Table name + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + body (FileUploadRequest): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, ErrorResponse, FileUploadResponse, HTTPValidationError] + """ + + return sync_detailed( + graph_id=graph_id, + table_name=table_name, + client=client, + body=body, + token=token, + authorization=authorization, + ).parsed + + +async def asyncio_detailed( + graph_id: str, + table_name: str, + *, + client: AuthenticatedClient, + body: FileUploadRequest, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Response[Union[Any, ErrorResponse, FileUploadResponse, HTTPValidationError]]: + r""" Get File Upload URL + + Generate a presigned S3 URL for secure file upload. + + **Purpose:** + Initiate file upload to a staging table by generating a secure, time-limited + presigned S3 URL. Files are uploaded directly to S3, bypassing the API for + optimal performance. + + **Upload Workflow:** + 1. Call this endpoint to get presigned URL + 2. PUT file directly to S3 URL (using curl, axios, etc.) + 3. Call PATCH /tables/files/{file_id} with status='uploaded' + 4. Backend validates file and calculates metrics + 5. File ready for ingestion + + **Supported Formats:** + - Parquet (`application/x-parquet` with `.parquet` extension) + - CSV (`text/csv` with `.csv` extension) + - JSON (`application/json` with `.json` extension) + + **Validation:** + - File extension must match content type + - File name 1-255 characters + - No path traversal characters (.. / \) + - Auto-creates table if it doesn't exist + + **Auto-Table Creation:** + If the table doesn't exist, it's automatically created with: + - Type inferred from name (e.g., \"Transaction\" → relationship) + - Empty schema (populated on ingestion) + - Ready for file uploads + + **Example Response:** + ```json + { + \"upload_url\": \"https://bucket.s3.amazonaws.com/path?X-Amz-Algorithm=...\", + \"expires_in\": 3600, + \"file_id\": \"f123-456-789\", + \"s3_key\": \"user-staging/user123/kg456/Entity/f123.../data.parquet\" + } + ``` + + **Example Usage:** + ```bash + # Step 1: Get upload URL + curl -X POST \"https://api.robosystems.ai/v1/graphs/kg123/tables/Entity/files\" \ + -H \"Authorization: Bearer YOUR_TOKEN\" \ + -H \"Content-Type: application/json\" \ + -d '{ + \"file_name\": \"entities.parquet\", + \"content_type\": \"application/x-parquet\" + }' + + # Step 2: Upload file directly to S3 + curl -X PUT \"$UPLOAD_URL\" \ + -H \"Content-Type: application/x-parquet\" \ + --data-binary \"@entities.parquet\" + + # Step 3: Mark as uploaded + curl -X PATCH \"https://api.robosystems.ai/v1/graphs/kg123/tables/files/$FILE_ID\" \ + -H \"Authorization: Bearer YOUR_TOKEN\" \ + -H \"Content-Type: application/json\" \ + -d '{\"status\": \"uploaded\"}' + ``` + + **Tips:** + - Presigned URLs expire (default: 1 hour) + - Use appropriate Content-Type header when uploading to S3 + - File extension must match content type + - Large files benefit from direct S3 upload + + **Note:** + Upload URL generation is included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + table_name (str): Table name + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + body (FileUploadRequest): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, ErrorResponse, FileUploadResponse, HTTPValidationError]] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + table_name=table_name, + body=body, + token=token, + authorization=authorization, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + graph_id: str, + table_name: str, + *, + client: AuthenticatedClient, + body: FileUploadRequest, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Optional[Union[Any, ErrorResponse, FileUploadResponse, HTTPValidationError]]: + r""" Get File Upload URL + + Generate a presigned S3 URL for secure file upload. + + **Purpose:** + Initiate file upload to a staging table by generating a secure, time-limited + presigned S3 URL. Files are uploaded directly to S3, bypassing the API for + optimal performance. + + **Upload Workflow:** + 1. Call this endpoint to get presigned URL + 2. PUT file directly to S3 URL (using curl, axios, etc.) + 3. Call PATCH /tables/files/{file_id} with status='uploaded' + 4. Backend validates file and calculates metrics + 5. File ready for ingestion + + **Supported Formats:** + - Parquet (`application/x-parquet` with `.parquet` extension) + - CSV (`text/csv` with `.csv` extension) + - JSON (`application/json` with `.json` extension) + + **Validation:** + - File extension must match content type + - File name 1-255 characters + - No path traversal characters (.. / \) + - Auto-creates table if it doesn't exist + + **Auto-Table Creation:** + If the table doesn't exist, it's automatically created with: + - Type inferred from name (e.g., \"Transaction\" → relationship) + - Empty schema (populated on ingestion) + - Ready for file uploads + + **Example Response:** + ```json + { + \"upload_url\": \"https://bucket.s3.amazonaws.com/path?X-Amz-Algorithm=...\", + \"expires_in\": 3600, + \"file_id\": \"f123-456-789\", + \"s3_key\": \"user-staging/user123/kg456/Entity/f123.../data.parquet\" + } + ``` + + **Example Usage:** + ```bash + # Step 1: Get upload URL + curl -X POST \"https://api.robosystems.ai/v1/graphs/kg123/tables/Entity/files\" \ + -H \"Authorization: Bearer YOUR_TOKEN\" \ + -H \"Content-Type: application/json\" \ + -d '{ + \"file_name\": \"entities.parquet\", + \"content_type\": \"application/x-parquet\" + }' + + # Step 2: Upload file directly to S3 + curl -X PUT \"$UPLOAD_URL\" \ + -H \"Content-Type: application/x-parquet\" \ + --data-binary \"@entities.parquet\" + + # Step 3: Mark as uploaded + curl -X PATCH \"https://api.robosystems.ai/v1/graphs/kg123/tables/files/$FILE_ID\" \ + -H \"Authorization: Bearer YOUR_TOKEN\" \ + -H \"Content-Type: application/json\" \ + -d '{\"status\": \"uploaded\"}' + ``` + + **Tips:** + - Presigned URLs expire (default: 1 hour) + - Use appropriate Content-Type header when uploading to S3 + - File extension must match content type + - Large files benefit from direct S3 upload + + **Note:** + Upload URL generation is included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + table_name (str): Table name + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + body (FileUploadRequest): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, ErrorResponse, FileUploadResponse, HTTPValidationError] + """ + + return ( + await asyncio_detailed( + graph_id=graph_id, + table_name=table_name, + client=client, + body=body, + token=token, + authorization=authorization, + ) + ).parsed diff --git a/robosystems_client/api/tables/get_upload_url_v1_graphs_graph_id_tables_table_name_files_post.py b/robosystems_client/api/tables/get_upload_url_v1_graphs_graph_id_tables_table_name_files_post.py deleted file mode 100644 index b823389..0000000 --- a/robosystems_client/api/tables/get_upload_url_v1_graphs_graph_id_tables_table_name_files_post.py +++ /dev/null @@ -1,260 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union, cast - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.error_response import ErrorResponse -from ...models.file_upload_request import FileUploadRequest -from ...models.file_upload_response import FileUploadResponse -from ...models.http_validation_error import HTTPValidationError -from ...types import UNSET, Response, Unset - - -def _get_kwargs( - graph_id: str, - table_name: str, - *, - body: FileUploadRequest, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - if not isinstance(authorization, Unset): - headers["authorization"] = authorization - - params: dict[str, Any] = {} - - json_token: Union[None, Unset, str] - if isinstance(token, Unset): - json_token = UNSET - else: - json_token = token - params["token"] = json_token - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "post", - "url": f"/v1/graphs/{graph_id}/tables/{table_name}/files", - "params": params, - } - - _kwargs["json"] = body.to_dict() - - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[Any, ErrorResponse, FileUploadResponse, HTTPValidationError]]: - if response.status_code == 200: - response_200 = FileUploadResponse.from_dict(response.json()) - - return response_200 - - if response.status_code == 400: - response_400 = ErrorResponse.from_dict(response.json()) - - return response_400 - - if response.status_code == 401: - response_401 = cast(Any, None) - return response_401 - - if response.status_code == 403: - response_403 = ErrorResponse.from_dict(response.json()) - - return response_403 - - if response.status_code == 404: - response_404 = ErrorResponse.from_dict(response.json()) - - return response_404 - - if response.status_code == 422: - response_422 = HTTPValidationError.from_dict(response.json()) - - return response_422 - - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[Any, ErrorResponse, FileUploadResponse, HTTPValidationError]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - graph_id: str, - table_name: str, - *, - client: AuthenticatedClient, - body: FileUploadRequest, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Response[Union[Any, ErrorResponse, FileUploadResponse, HTTPValidationError]]: - """Create File Upload - - Create a new file upload for a table and get a presigned S3 URL - - Args: - graph_id (str): Graph database identifier - table_name (str): Table name - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - body (FileUploadRequest): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, ErrorResponse, FileUploadResponse, HTTPValidationError]] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - table_name=table_name, - body=body, - token=token, - authorization=authorization, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - graph_id: str, - table_name: str, - *, - client: AuthenticatedClient, - body: FileUploadRequest, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Optional[Union[Any, ErrorResponse, FileUploadResponse, HTTPValidationError]]: - """Create File Upload - - Create a new file upload for a table and get a presigned S3 URL - - Args: - graph_id (str): Graph database identifier - table_name (str): Table name - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - body (FileUploadRequest): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, ErrorResponse, FileUploadResponse, HTTPValidationError] - """ - - return sync_detailed( - graph_id=graph_id, - table_name=table_name, - client=client, - body=body, - token=token, - authorization=authorization, - ).parsed - - -async def asyncio_detailed( - graph_id: str, - table_name: str, - *, - client: AuthenticatedClient, - body: FileUploadRequest, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Response[Union[Any, ErrorResponse, FileUploadResponse, HTTPValidationError]]: - """Create File Upload - - Create a new file upload for a table and get a presigned S3 URL - - Args: - graph_id (str): Graph database identifier - table_name (str): Table name - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - body (FileUploadRequest): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, ErrorResponse, FileUploadResponse, HTTPValidationError]] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - table_name=table_name, - body=body, - token=token, - authorization=authorization, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - graph_id: str, - table_name: str, - *, - client: AuthenticatedClient, - body: FileUploadRequest, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Optional[Union[Any, ErrorResponse, FileUploadResponse, HTTPValidationError]]: - """Create File Upload - - Create a new file upload for a table and get a presigned S3 URL - - Args: - graph_id (str): Graph database identifier - table_name (str): Table name - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - body (FileUploadRequest): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, ErrorResponse, FileUploadResponse, HTTPValidationError] - """ - - return ( - await asyncio_detailed( - graph_id=graph_id, - table_name=table_name, - client=client, - body=body, - token=token, - authorization=authorization, - ) - ).parsed diff --git a/robosystems_client/api/tables/ingest_tables.py b/robosystems_client/api/tables/ingest_tables.py new file mode 100644 index 0000000..4cd04ed --- /dev/null +++ b/robosystems_client/api/tables/ingest_tables.py @@ -0,0 +1,616 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.bulk_ingest_request import BulkIngestRequest +from ...models.bulk_ingest_response import BulkIngestResponse +from ...models.error_response import ErrorResponse +from ...models.http_validation_error import HTTPValidationError +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + graph_id: str, + *, + body: BulkIngestRequest, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + if not isinstance(authorization, Unset): + headers["authorization"] = authorization + + params: dict[str, Any] = {} + + json_token: Union[None, Unset, str] + if isinstance(token, Unset): + json_token = UNSET + else: + json_token = token + params["token"] = json_token + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": f"/v1/graphs/{graph_id}/tables/ingest", + "params": params, + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, BulkIngestResponse, ErrorResponse, HTTPValidationError]]: + if response.status_code == 200: + response_200 = BulkIngestResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = ErrorResponse.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ErrorResponse.from_dict(response.json()) + + return response_404 + + if response.status_code == 409: + response_409 = ErrorResponse.from_dict(response.json()) + + return response_409 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, BulkIngestResponse, ErrorResponse, HTTPValidationError]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + body: BulkIngestRequest, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Response[Union[Any, BulkIngestResponse, ErrorResponse, HTTPValidationError]]: + r""" Ingest Tables to Graph + + Load all files from S3 into DuckDB staging tables and ingest into Kuzu graph database. + + **Purpose:** + Orchestrates the complete data pipeline from S3 staging files into the Kuzu graph database. + Processes all tables in a single bulk operation with comprehensive error handling and metrics. + + **Use Cases:** + - Initial graph population from uploaded data + - Incremental data updates with new files + - Complete database rebuild from source files + - Recovery from failed ingestion attempts + + **Workflow:** + 1. Upload data files via `POST /tables/{table_name}/files` + 2. Files are validated and marked as 'uploaded' + 3. Trigger ingestion: `POST /tables/ingest` + 4. DuckDB staging tables created from S3 patterns + 5. Data copied row-by-row from DuckDB to Kuzu + 6. Per-table results and metrics returned + + **Rebuild Feature:** + Setting `rebuild=true` regenerates the entire graph database from scratch: + - Deletes existing Kuzu database + - Recreates with fresh schema from active GraphSchema + - Ingests all data files + - Safe operation - S3 is source of truth + - Useful for schema changes or data corrections + - Graph marked as 'rebuilding' during process + + **Error Handling:** + - Per-table error isolation with `ignore_errors` flag + - Partial success support (some tables succeed, some fail) + - Detailed error reporting per table + - Graph status tracking throughout process + - Automatic failure recovery and cleanup + + **Performance:** + - Processes all tables in sequence + - Each table timed independently + - Total execution metrics provided + - Scales to thousands of files + - Optimized for large datasets + + **Example Request:** + ```bash + curl -X POST \"https://api.robosystems.ai/v1/graphs/kg123/tables/ingest\" \ + -H \"Authorization: Bearer YOUR_TOKEN\" \ + -H \"Content-Type: application/json\" \ + -d '{ + \"ignore_errors\": true, + \"rebuild\": false + }' + ``` + + **Example Response:** + ```json + { + \"status\": \"success\", + \"graph_id\": \"kg123\", + \"total_tables\": 5, + \"successful_tables\": 5, + \"failed_tables\": 0, + \"skipped_tables\": 0, + \"total_rows_ingested\": 25000, + \"total_execution_time_ms\": 15420.5, + \"results\": [ + { + \"table_name\": \"Entity\", + \"status\": \"success\", + \"rows_ingested\": 5000, + \"execution_time_ms\": 3200.1, + \"error\": null + } + ] + } + ``` + + **Concurrency Control:** + Only one ingestion can run per graph at a time. If another ingestion is in progress, + you'll receive a 409 Conflict error. The distributed lock automatically expires after + the configured TTL (default: 1 hour) to prevent deadlocks from failed ingestions. + + **Tips:** + - Only files with 'uploaded' status are processed + - Tables with no uploaded files are skipped + - Use `ignore_errors=false` for strict validation + - Monitor progress via per-table results + - Check graph metadata for rebuild status + - Wait for current ingestion to complete before starting another + + **Note:** + Table ingestion is included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + body (BulkIngestRequest): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, BulkIngestResponse, ErrorResponse, HTTPValidationError]] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + body=body, + token=token, + authorization=authorization, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + graph_id: str, + *, + client: AuthenticatedClient, + body: BulkIngestRequest, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Optional[Union[Any, BulkIngestResponse, ErrorResponse, HTTPValidationError]]: + r""" Ingest Tables to Graph + + Load all files from S3 into DuckDB staging tables and ingest into Kuzu graph database. + + **Purpose:** + Orchestrates the complete data pipeline from S3 staging files into the Kuzu graph database. + Processes all tables in a single bulk operation with comprehensive error handling and metrics. + + **Use Cases:** + - Initial graph population from uploaded data + - Incremental data updates with new files + - Complete database rebuild from source files + - Recovery from failed ingestion attempts + + **Workflow:** + 1. Upload data files via `POST /tables/{table_name}/files` + 2. Files are validated and marked as 'uploaded' + 3. Trigger ingestion: `POST /tables/ingest` + 4. DuckDB staging tables created from S3 patterns + 5. Data copied row-by-row from DuckDB to Kuzu + 6. Per-table results and metrics returned + + **Rebuild Feature:** + Setting `rebuild=true` regenerates the entire graph database from scratch: + - Deletes existing Kuzu database + - Recreates with fresh schema from active GraphSchema + - Ingests all data files + - Safe operation - S3 is source of truth + - Useful for schema changes or data corrections + - Graph marked as 'rebuilding' during process + + **Error Handling:** + - Per-table error isolation with `ignore_errors` flag + - Partial success support (some tables succeed, some fail) + - Detailed error reporting per table + - Graph status tracking throughout process + - Automatic failure recovery and cleanup + + **Performance:** + - Processes all tables in sequence + - Each table timed independently + - Total execution metrics provided + - Scales to thousands of files + - Optimized for large datasets + + **Example Request:** + ```bash + curl -X POST \"https://api.robosystems.ai/v1/graphs/kg123/tables/ingest\" \ + -H \"Authorization: Bearer YOUR_TOKEN\" \ + -H \"Content-Type: application/json\" \ + -d '{ + \"ignore_errors\": true, + \"rebuild\": false + }' + ``` + + **Example Response:** + ```json + { + \"status\": \"success\", + \"graph_id\": \"kg123\", + \"total_tables\": 5, + \"successful_tables\": 5, + \"failed_tables\": 0, + \"skipped_tables\": 0, + \"total_rows_ingested\": 25000, + \"total_execution_time_ms\": 15420.5, + \"results\": [ + { + \"table_name\": \"Entity\", + \"status\": \"success\", + \"rows_ingested\": 5000, + \"execution_time_ms\": 3200.1, + \"error\": null + } + ] + } + ``` + + **Concurrency Control:** + Only one ingestion can run per graph at a time. If another ingestion is in progress, + you'll receive a 409 Conflict error. The distributed lock automatically expires after + the configured TTL (default: 1 hour) to prevent deadlocks from failed ingestions. + + **Tips:** + - Only files with 'uploaded' status are processed + - Tables with no uploaded files are skipped + - Use `ignore_errors=false` for strict validation + - Monitor progress via per-table results + - Check graph metadata for rebuild status + - Wait for current ingestion to complete before starting another + + **Note:** + Table ingestion is included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + body (BulkIngestRequest): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, BulkIngestResponse, ErrorResponse, HTTPValidationError] + """ + + return sync_detailed( + graph_id=graph_id, + client=client, + body=body, + token=token, + authorization=authorization, + ).parsed + + +async def asyncio_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + body: BulkIngestRequest, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Response[Union[Any, BulkIngestResponse, ErrorResponse, HTTPValidationError]]: + r""" Ingest Tables to Graph + + Load all files from S3 into DuckDB staging tables and ingest into Kuzu graph database. + + **Purpose:** + Orchestrates the complete data pipeline from S3 staging files into the Kuzu graph database. + Processes all tables in a single bulk operation with comprehensive error handling and metrics. + + **Use Cases:** + - Initial graph population from uploaded data + - Incremental data updates with new files + - Complete database rebuild from source files + - Recovery from failed ingestion attempts + + **Workflow:** + 1. Upload data files via `POST /tables/{table_name}/files` + 2. Files are validated and marked as 'uploaded' + 3. Trigger ingestion: `POST /tables/ingest` + 4. DuckDB staging tables created from S3 patterns + 5. Data copied row-by-row from DuckDB to Kuzu + 6. Per-table results and metrics returned + + **Rebuild Feature:** + Setting `rebuild=true` regenerates the entire graph database from scratch: + - Deletes existing Kuzu database + - Recreates with fresh schema from active GraphSchema + - Ingests all data files + - Safe operation - S3 is source of truth + - Useful for schema changes or data corrections + - Graph marked as 'rebuilding' during process + + **Error Handling:** + - Per-table error isolation with `ignore_errors` flag + - Partial success support (some tables succeed, some fail) + - Detailed error reporting per table + - Graph status tracking throughout process + - Automatic failure recovery and cleanup + + **Performance:** + - Processes all tables in sequence + - Each table timed independently + - Total execution metrics provided + - Scales to thousands of files + - Optimized for large datasets + + **Example Request:** + ```bash + curl -X POST \"https://api.robosystems.ai/v1/graphs/kg123/tables/ingest\" \ + -H \"Authorization: Bearer YOUR_TOKEN\" \ + -H \"Content-Type: application/json\" \ + -d '{ + \"ignore_errors\": true, + \"rebuild\": false + }' + ``` + + **Example Response:** + ```json + { + \"status\": \"success\", + \"graph_id\": \"kg123\", + \"total_tables\": 5, + \"successful_tables\": 5, + \"failed_tables\": 0, + \"skipped_tables\": 0, + \"total_rows_ingested\": 25000, + \"total_execution_time_ms\": 15420.5, + \"results\": [ + { + \"table_name\": \"Entity\", + \"status\": \"success\", + \"rows_ingested\": 5000, + \"execution_time_ms\": 3200.1, + \"error\": null + } + ] + } + ``` + + **Concurrency Control:** + Only one ingestion can run per graph at a time. If another ingestion is in progress, + you'll receive a 409 Conflict error. The distributed lock automatically expires after + the configured TTL (default: 1 hour) to prevent deadlocks from failed ingestions. + + **Tips:** + - Only files with 'uploaded' status are processed + - Tables with no uploaded files are skipped + - Use `ignore_errors=false` for strict validation + - Monitor progress via per-table results + - Check graph metadata for rebuild status + - Wait for current ingestion to complete before starting another + + **Note:** + Table ingestion is included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + body (BulkIngestRequest): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, BulkIngestResponse, ErrorResponse, HTTPValidationError]] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + body=body, + token=token, + authorization=authorization, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + graph_id: str, + *, + client: AuthenticatedClient, + body: BulkIngestRequest, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Optional[Union[Any, BulkIngestResponse, ErrorResponse, HTTPValidationError]]: + r""" Ingest Tables to Graph + + Load all files from S3 into DuckDB staging tables and ingest into Kuzu graph database. + + **Purpose:** + Orchestrates the complete data pipeline from S3 staging files into the Kuzu graph database. + Processes all tables in a single bulk operation with comprehensive error handling and metrics. + + **Use Cases:** + - Initial graph population from uploaded data + - Incremental data updates with new files + - Complete database rebuild from source files + - Recovery from failed ingestion attempts + + **Workflow:** + 1. Upload data files via `POST /tables/{table_name}/files` + 2. Files are validated and marked as 'uploaded' + 3. Trigger ingestion: `POST /tables/ingest` + 4. DuckDB staging tables created from S3 patterns + 5. Data copied row-by-row from DuckDB to Kuzu + 6. Per-table results and metrics returned + + **Rebuild Feature:** + Setting `rebuild=true` regenerates the entire graph database from scratch: + - Deletes existing Kuzu database + - Recreates with fresh schema from active GraphSchema + - Ingests all data files + - Safe operation - S3 is source of truth + - Useful for schema changes or data corrections + - Graph marked as 'rebuilding' during process + + **Error Handling:** + - Per-table error isolation with `ignore_errors` flag + - Partial success support (some tables succeed, some fail) + - Detailed error reporting per table + - Graph status tracking throughout process + - Automatic failure recovery and cleanup + + **Performance:** + - Processes all tables in sequence + - Each table timed independently + - Total execution metrics provided + - Scales to thousands of files + - Optimized for large datasets + + **Example Request:** + ```bash + curl -X POST \"https://api.robosystems.ai/v1/graphs/kg123/tables/ingest\" \ + -H \"Authorization: Bearer YOUR_TOKEN\" \ + -H \"Content-Type: application/json\" \ + -d '{ + \"ignore_errors\": true, + \"rebuild\": false + }' + ``` + + **Example Response:** + ```json + { + \"status\": \"success\", + \"graph_id\": \"kg123\", + \"total_tables\": 5, + \"successful_tables\": 5, + \"failed_tables\": 0, + \"skipped_tables\": 0, + \"total_rows_ingested\": 25000, + \"total_execution_time_ms\": 15420.5, + \"results\": [ + { + \"table_name\": \"Entity\", + \"status\": \"success\", + \"rows_ingested\": 5000, + \"execution_time_ms\": 3200.1, + \"error\": null + } + ] + } + ``` + + **Concurrency Control:** + Only one ingestion can run per graph at a time. If another ingestion is in progress, + you'll receive a 409 Conflict error. The distributed lock automatically expires after + the configured TTL (default: 1 hour) to prevent deadlocks from failed ingestions. + + **Tips:** + - Only files with 'uploaded' status are processed + - Tables with no uploaded files are skipped + - Use `ignore_errors=false` for strict validation + - Monitor progress via per-table results + - Check graph metadata for rebuild status + - Wait for current ingestion to complete before starting another + + **Note:** + Table ingestion is included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + body (BulkIngestRequest): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, BulkIngestResponse, ErrorResponse, HTTPValidationError] + """ + + return ( + await asyncio_detailed( + graph_id=graph_id, + client=client, + body=body, + token=token, + authorization=authorization, + ) + ).parsed diff --git a/robosystems_client/api/tables/ingest_tables_v1_graphs_graph_id_tables_ingest_post.py b/robosystems_client/api/tables/ingest_tables_v1_graphs_graph_id_tables_ingest_post.py deleted file mode 100644 index 144968d..0000000 --- a/robosystems_client/api/tables/ingest_tables_v1_graphs_graph_id_tables_ingest_post.py +++ /dev/null @@ -1,251 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union, cast - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.bulk_ingest_request import BulkIngestRequest -from ...models.bulk_ingest_response import BulkIngestResponse -from ...models.error_response import ErrorResponse -from ...models.http_validation_error import HTTPValidationError -from ...types import UNSET, Response, Unset - - -def _get_kwargs( - graph_id: str, - *, - body: BulkIngestRequest, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - if not isinstance(authorization, Unset): - headers["authorization"] = authorization - - params: dict[str, Any] = {} - - json_token: Union[None, Unset, str] - if isinstance(token, Unset): - json_token = UNSET - else: - json_token = token - params["token"] = json_token - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "post", - "url": f"/v1/graphs/{graph_id}/tables/ingest", - "params": params, - } - - _kwargs["json"] = body.to_dict() - - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[Any, BulkIngestResponse, ErrorResponse, HTTPValidationError]]: - if response.status_code == 200: - response_200 = BulkIngestResponse.from_dict(response.json()) - - return response_200 - - if response.status_code == 401: - response_401 = cast(Any, None) - return response_401 - - if response.status_code == 403: - response_403 = ErrorResponse.from_dict(response.json()) - - return response_403 - - if response.status_code == 404: - response_404 = ErrorResponse.from_dict(response.json()) - - return response_404 - - if response.status_code == 422: - response_422 = HTTPValidationError.from_dict(response.json()) - - return response_422 - - if response.status_code == 500: - response_500 = ErrorResponse.from_dict(response.json()) - - return response_500 - - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[Any, BulkIngestResponse, ErrorResponse, HTTPValidationError]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - graph_id: str, - *, - client: AuthenticatedClient, - body: BulkIngestRequest, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Response[Union[Any, BulkIngestResponse, ErrorResponse, HTTPValidationError]]: - """Ingest Tables to Graph - - Load all files from S3 into DuckDB staging tables and ingest into Kuzu graph database. Use - rebuild=true to regenerate the entire graph from scratch (safe operation - S3 is source of truth). - - Args: - graph_id (str): Graph database identifier - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - body (BulkIngestRequest): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, BulkIngestResponse, ErrorResponse, HTTPValidationError]] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - body=body, - token=token, - authorization=authorization, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - graph_id: str, - *, - client: AuthenticatedClient, - body: BulkIngestRequest, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Optional[Union[Any, BulkIngestResponse, ErrorResponse, HTTPValidationError]]: - """Ingest Tables to Graph - - Load all files from S3 into DuckDB staging tables and ingest into Kuzu graph database. Use - rebuild=true to regenerate the entire graph from scratch (safe operation - S3 is source of truth). - - Args: - graph_id (str): Graph database identifier - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - body (BulkIngestRequest): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, BulkIngestResponse, ErrorResponse, HTTPValidationError] - """ - - return sync_detailed( - graph_id=graph_id, - client=client, - body=body, - token=token, - authorization=authorization, - ).parsed - - -async def asyncio_detailed( - graph_id: str, - *, - client: AuthenticatedClient, - body: BulkIngestRequest, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Response[Union[Any, BulkIngestResponse, ErrorResponse, HTTPValidationError]]: - """Ingest Tables to Graph - - Load all files from S3 into DuckDB staging tables and ingest into Kuzu graph database. Use - rebuild=true to regenerate the entire graph from scratch (safe operation - S3 is source of truth). - - Args: - graph_id (str): Graph database identifier - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - body (BulkIngestRequest): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, BulkIngestResponse, ErrorResponse, HTTPValidationError]] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - body=body, - token=token, - authorization=authorization, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - graph_id: str, - *, - client: AuthenticatedClient, - body: BulkIngestRequest, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Optional[Union[Any, BulkIngestResponse, ErrorResponse, HTTPValidationError]]: - """Ingest Tables to Graph - - Load all files from S3 into DuckDB staging tables and ingest into Kuzu graph database. Use - rebuild=true to regenerate the entire graph from scratch (safe operation - S3 is source of truth). - - Args: - graph_id (str): Graph database identifier - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - body (BulkIngestRequest): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, BulkIngestResponse, ErrorResponse, HTTPValidationError] - """ - - return ( - await asyncio_detailed( - graph_id=graph_id, - client=client, - body=body, - token=token, - authorization=authorization, - ) - ).parsed diff --git a/robosystems_client/api/tables/list_table_files.py b/robosystems_client/api/tables/list_table_files.py new file mode 100644 index 0000000..f969357 --- /dev/null +++ b/robosystems_client/api/tables/list_table_files.py @@ -0,0 +1,509 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error_response import ErrorResponse +from ...models.http_validation_error import HTTPValidationError +from ...models.list_table_files_response import ListTableFilesResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + graph_id: str, + table_name: str, + *, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + if not isinstance(authorization, Unset): + headers["authorization"] = authorization + + params: dict[str, Any] = {} + + json_token: Union[None, Unset, str] + if isinstance(token, Unset): + json_token = UNSET + else: + json_token = token + params["token"] = json_token + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/v1/graphs/{graph_id}/tables/{table_name}/files", + "params": params, + } + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, ErrorResponse, HTTPValidationError, ListTableFilesResponse]]: + if response.status_code == 200: + response_200 = ListTableFilesResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = ErrorResponse.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ErrorResponse.from_dict(response.json()) + + return response_404 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if response.status_code == 500: + response_500 = cast(Any, None) + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, ErrorResponse, HTTPValidationError, ListTableFilesResponse]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + graph_id: str, + table_name: str, + *, + client: AuthenticatedClient, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Response[Union[Any, ErrorResponse, HTTPValidationError, ListTableFilesResponse]]: + r""" List Files in Staging Table + + List all files uploaded to a staging table with comprehensive metadata. + + **Purpose:** + Get a complete inventory of all files in a staging table, including upload status, + file sizes, row counts, and S3 locations. Essential for monitoring upload progress + and validating data before ingestion. + + **Use Cases:** + - Monitor file upload progress + - Verify files are ready for ingestion + - Check file formats and sizes + - Track storage usage per table + - Identify failed or incomplete uploads + - Pre-ingestion validation + + **What You Get:** + - File ID and name + - File format (parquet, csv, etc.) + - Size in bytes + - Row count (if available) + - Upload status and method + - Creation and upload timestamps + - S3 key for reference + + **Upload Status Values:** + - `created`: File record created, not yet uploaded + - `uploading`: Upload in progress + - `uploaded`: Successfully uploaded, ready for ingestion + - `failed`: Upload failed + + **Example Response:** + ```json + { + \"graph_id\": \"kg123\", + \"table_name\": \"Entity\", + \"files\": [ + { + \"file_id\": \"f123\", + \"file_name\": \"entities_batch1.parquet\", + \"file_format\": \"parquet\", + \"size_bytes\": 1048576, + \"row_count\": 5000, + \"upload_status\": \"uploaded\", + \"upload_method\": \"presigned_url\", + \"created_at\": \"2025-10-28T10:00:00Z\", + \"uploaded_at\": \"2025-10-28T10:01:30Z\", + \"s3_key\": \"user-staging/user123/kg123/Entity/entities_batch1.parquet\" + } + ], + \"total_files\": 1, + \"total_size_bytes\": 1048576 + } + ``` + + **Example Usage:** + ```bash + curl -H \"Authorization: Bearer YOUR_TOKEN\" \ + https://api.robosystems.ai/v1/graphs/kg123/tables/Entity/files + ``` + + **Tips:** + - Only `uploaded` files are ingested + - Check `row_count` to estimate data volume + - Use `total_size_bytes` for storage monitoring + - Files with `failed` status should be deleted and re-uploaded + + **Note:** + File listing is included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + table_name (str): Table name + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, ErrorResponse, HTTPValidationError, ListTableFilesResponse]] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + table_name=table_name, + token=token, + authorization=authorization, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + graph_id: str, + table_name: str, + *, + client: AuthenticatedClient, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Optional[Union[Any, ErrorResponse, HTTPValidationError, ListTableFilesResponse]]: + r""" List Files in Staging Table + + List all files uploaded to a staging table with comprehensive metadata. + + **Purpose:** + Get a complete inventory of all files in a staging table, including upload status, + file sizes, row counts, and S3 locations. Essential for monitoring upload progress + and validating data before ingestion. + + **Use Cases:** + - Monitor file upload progress + - Verify files are ready for ingestion + - Check file formats and sizes + - Track storage usage per table + - Identify failed or incomplete uploads + - Pre-ingestion validation + + **What You Get:** + - File ID and name + - File format (parquet, csv, etc.) + - Size in bytes + - Row count (if available) + - Upload status and method + - Creation and upload timestamps + - S3 key for reference + + **Upload Status Values:** + - `created`: File record created, not yet uploaded + - `uploading`: Upload in progress + - `uploaded`: Successfully uploaded, ready for ingestion + - `failed`: Upload failed + + **Example Response:** + ```json + { + \"graph_id\": \"kg123\", + \"table_name\": \"Entity\", + \"files\": [ + { + \"file_id\": \"f123\", + \"file_name\": \"entities_batch1.parquet\", + \"file_format\": \"parquet\", + \"size_bytes\": 1048576, + \"row_count\": 5000, + \"upload_status\": \"uploaded\", + \"upload_method\": \"presigned_url\", + \"created_at\": \"2025-10-28T10:00:00Z\", + \"uploaded_at\": \"2025-10-28T10:01:30Z\", + \"s3_key\": \"user-staging/user123/kg123/Entity/entities_batch1.parquet\" + } + ], + \"total_files\": 1, + \"total_size_bytes\": 1048576 + } + ``` + + **Example Usage:** + ```bash + curl -H \"Authorization: Bearer YOUR_TOKEN\" \ + https://api.robosystems.ai/v1/graphs/kg123/tables/Entity/files + ``` + + **Tips:** + - Only `uploaded` files are ingested + - Check `row_count` to estimate data volume + - Use `total_size_bytes` for storage monitoring + - Files with `failed` status should be deleted and re-uploaded + + **Note:** + File listing is included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + table_name (str): Table name + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, ErrorResponse, HTTPValidationError, ListTableFilesResponse] + """ + + return sync_detailed( + graph_id=graph_id, + table_name=table_name, + client=client, + token=token, + authorization=authorization, + ).parsed + + +async def asyncio_detailed( + graph_id: str, + table_name: str, + *, + client: AuthenticatedClient, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Response[Union[Any, ErrorResponse, HTTPValidationError, ListTableFilesResponse]]: + r""" List Files in Staging Table + + List all files uploaded to a staging table with comprehensive metadata. + + **Purpose:** + Get a complete inventory of all files in a staging table, including upload status, + file sizes, row counts, and S3 locations. Essential for monitoring upload progress + and validating data before ingestion. + + **Use Cases:** + - Monitor file upload progress + - Verify files are ready for ingestion + - Check file formats and sizes + - Track storage usage per table + - Identify failed or incomplete uploads + - Pre-ingestion validation + + **What You Get:** + - File ID and name + - File format (parquet, csv, etc.) + - Size in bytes + - Row count (if available) + - Upload status and method + - Creation and upload timestamps + - S3 key for reference + + **Upload Status Values:** + - `created`: File record created, not yet uploaded + - `uploading`: Upload in progress + - `uploaded`: Successfully uploaded, ready for ingestion + - `failed`: Upload failed + + **Example Response:** + ```json + { + \"graph_id\": \"kg123\", + \"table_name\": \"Entity\", + \"files\": [ + { + \"file_id\": \"f123\", + \"file_name\": \"entities_batch1.parquet\", + \"file_format\": \"parquet\", + \"size_bytes\": 1048576, + \"row_count\": 5000, + \"upload_status\": \"uploaded\", + \"upload_method\": \"presigned_url\", + \"created_at\": \"2025-10-28T10:00:00Z\", + \"uploaded_at\": \"2025-10-28T10:01:30Z\", + \"s3_key\": \"user-staging/user123/kg123/Entity/entities_batch1.parquet\" + } + ], + \"total_files\": 1, + \"total_size_bytes\": 1048576 + } + ``` + + **Example Usage:** + ```bash + curl -H \"Authorization: Bearer YOUR_TOKEN\" \ + https://api.robosystems.ai/v1/graphs/kg123/tables/Entity/files + ``` + + **Tips:** + - Only `uploaded` files are ingested + - Check `row_count` to estimate data volume + - Use `total_size_bytes` for storage monitoring + - Files with `failed` status should be deleted and re-uploaded + + **Note:** + File listing is included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + table_name (str): Table name + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, ErrorResponse, HTTPValidationError, ListTableFilesResponse]] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + table_name=table_name, + token=token, + authorization=authorization, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + graph_id: str, + table_name: str, + *, + client: AuthenticatedClient, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Optional[Union[Any, ErrorResponse, HTTPValidationError, ListTableFilesResponse]]: + r""" List Files in Staging Table + + List all files uploaded to a staging table with comprehensive metadata. + + **Purpose:** + Get a complete inventory of all files in a staging table, including upload status, + file sizes, row counts, and S3 locations. Essential for monitoring upload progress + and validating data before ingestion. + + **Use Cases:** + - Monitor file upload progress + - Verify files are ready for ingestion + - Check file formats and sizes + - Track storage usage per table + - Identify failed or incomplete uploads + - Pre-ingestion validation + + **What You Get:** + - File ID and name + - File format (parquet, csv, etc.) + - Size in bytes + - Row count (if available) + - Upload status and method + - Creation and upload timestamps + - S3 key for reference + + **Upload Status Values:** + - `created`: File record created, not yet uploaded + - `uploading`: Upload in progress + - `uploaded`: Successfully uploaded, ready for ingestion + - `failed`: Upload failed + + **Example Response:** + ```json + { + \"graph_id\": \"kg123\", + \"table_name\": \"Entity\", + \"files\": [ + { + \"file_id\": \"f123\", + \"file_name\": \"entities_batch1.parquet\", + \"file_format\": \"parquet\", + \"size_bytes\": 1048576, + \"row_count\": 5000, + \"upload_status\": \"uploaded\", + \"upload_method\": \"presigned_url\", + \"created_at\": \"2025-10-28T10:00:00Z\", + \"uploaded_at\": \"2025-10-28T10:01:30Z\", + \"s3_key\": \"user-staging/user123/kg123/Entity/entities_batch1.parquet\" + } + ], + \"total_files\": 1, + \"total_size_bytes\": 1048576 + } + ``` + + **Example Usage:** + ```bash + curl -H \"Authorization: Bearer YOUR_TOKEN\" \ + https://api.robosystems.ai/v1/graphs/kg123/tables/Entity/files + ``` + + **Tips:** + - Only `uploaded` files are ingested + - Check `row_count` to estimate data volume + - Use `total_size_bytes` for storage monitoring + - Files with `failed` status should be deleted and re-uploaded + + **Note:** + File listing is included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + table_name (str): Table name + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, ErrorResponse, HTTPValidationError, ListTableFilesResponse] + """ + + return ( + await asyncio_detailed( + graph_id=graph_id, + table_name=table_name, + client=client, + token=token, + authorization=authorization, + ) + ).parsed diff --git a/robosystems_client/api/tables/list_table_files_v1_graphs_graph_id_tables_table_name_files_get.py b/robosystems_client/api/tables/list_table_files_v1_graphs_graph_id_tables_table_name_files_get.py deleted file mode 100644 index bb85bf0..0000000 --- a/robosystems_client/api/tables/list_table_files_v1_graphs_graph_id_tables_table_name_files_get.py +++ /dev/null @@ -1,283 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union, cast - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.error_response import ErrorResponse -from ...models.http_validation_error import HTTPValidationError -from ...models.list_table_files_v1_graphs_graph_id_tables_table_name_files_get_response_list_table_files_v1_graphs_graph_id_tables_table_name_files_get import ( - ListTableFilesV1GraphsGraphIdTablesTableNameFilesGetResponseListTableFilesV1GraphsGraphIdTablesTableNameFilesGet, -) -from ...types import UNSET, Response, Unset - - -def _get_kwargs( - graph_id: str, - table_name: str, - *, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - if not isinstance(authorization, Unset): - headers["authorization"] = authorization - - params: dict[str, Any] = {} - - json_token: Union[None, Unset, str] - if isinstance(token, Unset): - json_token = UNSET - else: - json_token = token - params["token"] = json_token - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "get", - "url": f"/v1/graphs/{graph_id}/tables/{table_name}/files", - "params": params, - } - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[ - Union[ - Any, - ErrorResponse, - HTTPValidationError, - ListTableFilesV1GraphsGraphIdTablesTableNameFilesGetResponseListTableFilesV1GraphsGraphIdTablesTableNameFilesGet, - ] -]: - if response.status_code == 200: - response_200 = ListTableFilesV1GraphsGraphIdTablesTableNameFilesGetResponseListTableFilesV1GraphsGraphIdTablesTableNameFilesGet.from_dict( - response.json() - ) - - return response_200 - - if response.status_code == 401: - response_401 = cast(Any, None) - return response_401 - - if response.status_code == 403: - response_403 = ErrorResponse.from_dict(response.json()) - - return response_403 - - if response.status_code == 404: - response_404 = ErrorResponse.from_dict(response.json()) - - return response_404 - - if response.status_code == 422: - response_422 = HTTPValidationError.from_dict(response.json()) - - return response_422 - - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[ - Union[ - Any, - ErrorResponse, - HTTPValidationError, - ListTableFilesV1GraphsGraphIdTablesTableNameFilesGetResponseListTableFilesV1GraphsGraphIdTablesTableNameFilesGet, - ] -]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - graph_id: str, - table_name: str, - *, - client: AuthenticatedClient, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Response[ - Union[ - Any, - ErrorResponse, - HTTPValidationError, - ListTableFilesV1GraphsGraphIdTablesTableNameFilesGetResponseListTableFilesV1GraphsGraphIdTablesTableNameFilesGet, - ] -]: - """List Files in Table - - List all files uploaded to a staging table - - Args: - graph_id (str): Graph database identifier - table_name (str): Table name - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, ErrorResponse, HTTPValidationError, ListTableFilesV1GraphsGraphIdTablesTableNameFilesGetResponseListTableFilesV1GraphsGraphIdTablesTableNameFilesGet]] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - table_name=table_name, - token=token, - authorization=authorization, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - graph_id: str, - table_name: str, - *, - client: AuthenticatedClient, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Optional[ - Union[ - Any, - ErrorResponse, - HTTPValidationError, - ListTableFilesV1GraphsGraphIdTablesTableNameFilesGetResponseListTableFilesV1GraphsGraphIdTablesTableNameFilesGet, - ] -]: - """List Files in Table - - List all files uploaded to a staging table - - Args: - graph_id (str): Graph database identifier - table_name (str): Table name - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, ErrorResponse, HTTPValidationError, ListTableFilesV1GraphsGraphIdTablesTableNameFilesGetResponseListTableFilesV1GraphsGraphIdTablesTableNameFilesGet] - """ - - return sync_detailed( - graph_id=graph_id, - table_name=table_name, - client=client, - token=token, - authorization=authorization, - ).parsed - - -async def asyncio_detailed( - graph_id: str, - table_name: str, - *, - client: AuthenticatedClient, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Response[ - Union[ - Any, - ErrorResponse, - HTTPValidationError, - ListTableFilesV1GraphsGraphIdTablesTableNameFilesGetResponseListTableFilesV1GraphsGraphIdTablesTableNameFilesGet, - ] -]: - """List Files in Table - - List all files uploaded to a staging table - - Args: - graph_id (str): Graph database identifier - table_name (str): Table name - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, ErrorResponse, HTTPValidationError, ListTableFilesV1GraphsGraphIdTablesTableNameFilesGetResponseListTableFilesV1GraphsGraphIdTablesTableNameFilesGet]] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - table_name=table_name, - token=token, - authorization=authorization, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - graph_id: str, - table_name: str, - *, - client: AuthenticatedClient, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Optional[ - Union[ - Any, - ErrorResponse, - HTTPValidationError, - ListTableFilesV1GraphsGraphIdTablesTableNameFilesGetResponseListTableFilesV1GraphsGraphIdTablesTableNameFilesGet, - ] -]: - """List Files in Table - - List all files uploaded to a staging table - - Args: - graph_id (str): Graph database identifier - table_name (str): Table name - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, ErrorResponse, HTTPValidationError, ListTableFilesV1GraphsGraphIdTablesTableNameFilesGetResponseListTableFilesV1GraphsGraphIdTablesTableNameFilesGet] - """ - - return ( - await asyncio_detailed( - graph_id=graph_id, - table_name=table_name, - client=client, - token=token, - authorization=authorization, - ) - ).parsed diff --git a/robosystems_client/api/tables/list_tables.py b/robosystems_client/api/tables/list_tables.py new file mode 100644 index 0000000..64255ee --- /dev/null +++ b/robosystems_client/api/tables/list_tables.py @@ -0,0 +1,488 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error_response import ErrorResponse +from ...models.http_validation_error import HTTPValidationError +from ...models.table_list_response import TableListResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + graph_id: str, + *, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + if not isinstance(authorization, Unset): + headers["authorization"] = authorization + + params: dict[str, Any] = {} + + json_token: Union[None, Unset, str] + if isinstance(token, Unset): + json_token = UNSET + else: + json_token = token + params["token"] = json_token + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/v1/graphs/{graph_id}/tables", + "params": params, + } + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, ErrorResponse, HTTPValidationError, TableListResponse]]: + if response.status_code == 200: + response_200 = TableListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = ErrorResponse.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ErrorResponse.from_dict(response.json()) + + return response_404 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if response.status_code == 500: + response_500 = cast(Any, None) + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, ErrorResponse, HTTPValidationError, TableListResponse]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Response[Union[Any, ErrorResponse, HTTPValidationError, TableListResponse]]: + r""" List Staging Tables + + List all DuckDB staging tables with comprehensive metrics and status. + + **Purpose:** + Get a complete inventory of all staging tables for a graph, including + file counts, storage sizes, and row estimates. Essential for monitoring + the data pipeline and determining which tables are ready for ingestion. + + **What You Get:** + - Table name and type (node/relationship) + - File count per table + - Total storage size in bytes + - Estimated row count + - S3 location pattern + - Ready-for-ingestion status + + **Use Cases:** + - Monitor data upload progress + - Check which tables have files ready + - Track storage consumption + - Validate pipeline before ingestion + - Capacity planning + + **Workflow:** + 1. List tables to see current state + 2. Upload files to empty tables + 3. Re-list to verify uploads + 4. Check file counts and sizes + 5. Ingest when ready + + **Example Response:** + ```json + { + \"tables\": [ + { + \"table_name\": \"Entity\", + \"row_count\": 5000, + \"file_count\": 3, + \"total_size_bytes\": 2457600, + \"s3_location\": \"s3://bucket/user-staging/user123/graph456/Entity/**/*.parquet\" + }, + { + \"table_name\": \"Transaction\", + \"row_count\": 15000, + \"file_count\": 5, + \"total_size_bytes\": 8192000, + \"s3_location\": \"s3://bucket/user-staging/user123/graph456/Transaction/**/*.parquet\" + } + ], + \"total_count\": 2 + } + ``` + + **Example Usage:** + ```bash + curl -H \"Authorization: Bearer YOUR_TOKEN\" \ + https://api.robosystems.ai/v1/graphs/kg123/tables + ``` + + **Tips:** + - Tables with `file_count > 0` have data ready + - Check `total_size_bytes` for storage monitoring + - Use `s3_location` to verify upload paths + - Empty tables (file_count=0) are skipped during ingestion + + **Note:** + Table queries are included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, ErrorResponse, HTTPValidationError, TableListResponse]] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + token=token, + authorization=authorization, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + graph_id: str, + *, + client: AuthenticatedClient, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Optional[Union[Any, ErrorResponse, HTTPValidationError, TableListResponse]]: + r""" List Staging Tables + + List all DuckDB staging tables with comprehensive metrics and status. + + **Purpose:** + Get a complete inventory of all staging tables for a graph, including + file counts, storage sizes, and row estimates. Essential for monitoring + the data pipeline and determining which tables are ready for ingestion. + + **What You Get:** + - Table name and type (node/relationship) + - File count per table + - Total storage size in bytes + - Estimated row count + - S3 location pattern + - Ready-for-ingestion status + + **Use Cases:** + - Monitor data upload progress + - Check which tables have files ready + - Track storage consumption + - Validate pipeline before ingestion + - Capacity planning + + **Workflow:** + 1. List tables to see current state + 2. Upload files to empty tables + 3. Re-list to verify uploads + 4. Check file counts and sizes + 5. Ingest when ready + + **Example Response:** + ```json + { + \"tables\": [ + { + \"table_name\": \"Entity\", + \"row_count\": 5000, + \"file_count\": 3, + \"total_size_bytes\": 2457600, + \"s3_location\": \"s3://bucket/user-staging/user123/graph456/Entity/**/*.parquet\" + }, + { + \"table_name\": \"Transaction\", + \"row_count\": 15000, + \"file_count\": 5, + \"total_size_bytes\": 8192000, + \"s3_location\": \"s3://bucket/user-staging/user123/graph456/Transaction/**/*.parquet\" + } + ], + \"total_count\": 2 + } + ``` + + **Example Usage:** + ```bash + curl -H \"Authorization: Bearer YOUR_TOKEN\" \ + https://api.robosystems.ai/v1/graphs/kg123/tables + ``` + + **Tips:** + - Tables with `file_count > 0` have data ready + - Check `total_size_bytes` for storage monitoring + - Use `s3_location` to verify upload paths + - Empty tables (file_count=0) are skipped during ingestion + + **Note:** + Table queries are included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, ErrorResponse, HTTPValidationError, TableListResponse] + """ + + return sync_detailed( + graph_id=graph_id, + client=client, + token=token, + authorization=authorization, + ).parsed + + +async def asyncio_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Response[Union[Any, ErrorResponse, HTTPValidationError, TableListResponse]]: + r""" List Staging Tables + + List all DuckDB staging tables with comprehensive metrics and status. + + **Purpose:** + Get a complete inventory of all staging tables for a graph, including + file counts, storage sizes, and row estimates. Essential for monitoring + the data pipeline and determining which tables are ready for ingestion. + + **What You Get:** + - Table name and type (node/relationship) + - File count per table + - Total storage size in bytes + - Estimated row count + - S3 location pattern + - Ready-for-ingestion status + + **Use Cases:** + - Monitor data upload progress + - Check which tables have files ready + - Track storage consumption + - Validate pipeline before ingestion + - Capacity planning + + **Workflow:** + 1. List tables to see current state + 2. Upload files to empty tables + 3. Re-list to verify uploads + 4. Check file counts and sizes + 5. Ingest when ready + + **Example Response:** + ```json + { + \"tables\": [ + { + \"table_name\": \"Entity\", + \"row_count\": 5000, + \"file_count\": 3, + \"total_size_bytes\": 2457600, + \"s3_location\": \"s3://bucket/user-staging/user123/graph456/Entity/**/*.parquet\" + }, + { + \"table_name\": \"Transaction\", + \"row_count\": 15000, + \"file_count\": 5, + \"total_size_bytes\": 8192000, + \"s3_location\": \"s3://bucket/user-staging/user123/graph456/Transaction/**/*.parquet\" + } + ], + \"total_count\": 2 + } + ``` + + **Example Usage:** + ```bash + curl -H \"Authorization: Bearer YOUR_TOKEN\" \ + https://api.robosystems.ai/v1/graphs/kg123/tables + ``` + + **Tips:** + - Tables with `file_count > 0` have data ready + - Check `total_size_bytes` for storage monitoring + - Use `s3_location` to verify upload paths + - Empty tables (file_count=0) are skipped during ingestion + + **Note:** + Table queries are included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, ErrorResponse, HTTPValidationError, TableListResponse]] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + token=token, + authorization=authorization, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + graph_id: str, + *, + client: AuthenticatedClient, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Optional[Union[Any, ErrorResponse, HTTPValidationError, TableListResponse]]: + r""" List Staging Tables + + List all DuckDB staging tables with comprehensive metrics and status. + + **Purpose:** + Get a complete inventory of all staging tables for a graph, including + file counts, storage sizes, and row estimates. Essential for monitoring + the data pipeline and determining which tables are ready for ingestion. + + **What You Get:** + - Table name and type (node/relationship) + - File count per table + - Total storage size in bytes + - Estimated row count + - S3 location pattern + - Ready-for-ingestion status + + **Use Cases:** + - Monitor data upload progress + - Check which tables have files ready + - Track storage consumption + - Validate pipeline before ingestion + - Capacity planning + + **Workflow:** + 1. List tables to see current state + 2. Upload files to empty tables + 3. Re-list to verify uploads + 4. Check file counts and sizes + 5. Ingest when ready + + **Example Response:** + ```json + { + \"tables\": [ + { + \"table_name\": \"Entity\", + \"row_count\": 5000, + \"file_count\": 3, + \"total_size_bytes\": 2457600, + \"s3_location\": \"s3://bucket/user-staging/user123/graph456/Entity/**/*.parquet\" + }, + { + \"table_name\": \"Transaction\", + \"row_count\": 15000, + \"file_count\": 5, + \"total_size_bytes\": 8192000, + \"s3_location\": \"s3://bucket/user-staging/user123/graph456/Transaction/**/*.parquet\" + } + ], + \"total_count\": 2 + } + ``` + + **Example Usage:** + ```bash + curl -H \"Authorization: Bearer YOUR_TOKEN\" \ + https://api.robosystems.ai/v1/graphs/kg123/tables + ``` + + **Tips:** + - Tables with `file_count > 0` have data ready + - Check `total_size_bytes` for storage monitoring + - Use `s3_location` to verify upload paths + - Empty tables (file_count=0) are skipped during ingestion + + **Note:** + Table queries are included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, ErrorResponse, HTTPValidationError, TableListResponse] + """ + + return ( + await asyncio_detailed( + graph_id=graph_id, + client=client, + token=token, + authorization=authorization, + ) + ).parsed diff --git a/robosystems_client/api/tables/list_tables_v1_graphs_graph_id_tables_get.py b/robosystems_client/api/tables/list_tables_v1_graphs_graph_id_tables_get.py deleted file mode 100644 index 9dbd7f4..0000000 --- a/robosystems_client/api/tables/list_tables_v1_graphs_graph_id_tables_get.py +++ /dev/null @@ -1,224 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union, cast - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.error_response import ErrorResponse -from ...models.http_validation_error import HTTPValidationError -from ...models.table_list_response import TableListResponse -from ...types import UNSET, Response, Unset - - -def _get_kwargs( - graph_id: str, - *, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - if not isinstance(authorization, Unset): - headers["authorization"] = authorization - - params: dict[str, Any] = {} - - json_token: Union[None, Unset, str] - if isinstance(token, Unset): - json_token = UNSET - else: - json_token = token - params["token"] = json_token - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "get", - "url": f"/v1/graphs/{graph_id}/tables", - "params": params, - } - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[Any, ErrorResponse, HTTPValidationError, TableListResponse]]: - if response.status_code == 200: - response_200 = TableListResponse.from_dict(response.json()) - - return response_200 - - if response.status_code == 401: - response_401 = cast(Any, None) - return response_401 - - if response.status_code == 403: - response_403 = ErrorResponse.from_dict(response.json()) - - return response_403 - - if response.status_code == 404: - response_404 = ErrorResponse.from_dict(response.json()) - - return response_404 - - if response.status_code == 422: - response_422 = HTTPValidationError.from_dict(response.json()) - - return response_422 - - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[Any, ErrorResponse, HTTPValidationError, TableListResponse]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - graph_id: str, - *, - client: AuthenticatedClient, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Response[Union[Any, ErrorResponse, HTTPValidationError, TableListResponse]]: - """List Staging Tables - - List all DuckDB staging tables for a graph - - Args: - graph_id (str): Graph database identifier - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, ErrorResponse, HTTPValidationError, TableListResponse]] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - token=token, - authorization=authorization, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - graph_id: str, - *, - client: AuthenticatedClient, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Optional[Union[Any, ErrorResponse, HTTPValidationError, TableListResponse]]: - """List Staging Tables - - List all DuckDB staging tables for a graph - - Args: - graph_id (str): Graph database identifier - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, ErrorResponse, HTTPValidationError, TableListResponse] - """ - - return sync_detailed( - graph_id=graph_id, - client=client, - token=token, - authorization=authorization, - ).parsed - - -async def asyncio_detailed( - graph_id: str, - *, - client: AuthenticatedClient, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Response[Union[Any, ErrorResponse, HTTPValidationError, TableListResponse]]: - """List Staging Tables - - List all DuckDB staging tables for a graph - - Args: - graph_id (str): Graph database identifier - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, ErrorResponse, HTTPValidationError, TableListResponse]] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - token=token, - authorization=authorization, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - graph_id: str, - *, - client: AuthenticatedClient, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Optional[Union[Any, ErrorResponse, HTTPValidationError, TableListResponse]]: - """List Staging Tables - - List all DuckDB staging tables for a graph - - Args: - graph_id (str): Graph database identifier - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, ErrorResponse, HTTPValidationError, TableListResponse] - """ - - return ( - await asyncio_detailed( - graph_id=graph_id, - client=client, - token=token, - authorization=authorization, - ) - ).parsed diff --git a/robosystems_client/api/tables/query_tables.py b/robosystems_client/api/tables/query_tables.py new file mode 100644 index 0000000..9d07827 --- /dev/null +++ b/robosystems_client/api/tables/query_tables.py @@ -0,0 +1,487 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error_response import ErrorResponse +from ...models.http_validation_error import HTTPValidationError +from ...models.table_query_request import TableQueryRequest +from ...models.table_query_response import TableQueryResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + graph_id: str, + *, + body: TableQueryRequest, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + if not isinstance(authorization, Unset): + headers["authorization"] = authorization + + params: dict[str, Any] = {} + + json_token: Union[None, Unset, str] + if isinstance(token, Unset): + json_token = UNSET + else: + json_token = token + params["token"] = json_token + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": f"/v1/graphs/{graph_id}/tables/query", + "params": params, + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, ErrorResponse, HTTPValidationError, TableQueryResponse]]: + if response.status_code == 200: + response_200 = TableQueryResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = ErrorResponse.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ErrorResponse.from_dict(response.json()) + + return response_404 + + if response.status_code == 408: + response_408 = cast(Any, None) + return response_408 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if response.status_code == 500: + response_500 = cast(Any, None) + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, ErrorResponse, HTTPValidationError, TableQueryResponse]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + body: TableQueryRequest, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Response[Union[Any, ErrorResponse, HTTPValidationError, TableQueryResponse]]: + """Query Staging Tables with SQL + + Execute SQL queries on DuckDB staging tables for data inspection and validation. + + **Purpose:** + Query raw staging data directly with SQL before ingestion into the graph database. + Useful for data quality checks, validation, and exploratory analysis. + + **Use Cases:** + - Validate data quality before graph ingestion + - Inspect row-level data for debugging + - Run analytics on staging tables + - Check for duplicates, nulls, or data issues + - Preview data transformations + + **Workflow:** + 1. Upload data files via `POST /tables/{table_name}/files` + 2. Query staging tables to validate: `POST /tables/query` + 3. Fix any data issues by re-uploading + 4. Ingest validated data: `POST /tables/ingest` + + **Supported SQL:** + - Full DuckDB SQL syntax + - SELECT, JOIN, WHERE, GROUP BY, ORDER BY + - Aggregations, window functions, CTEs + - Multiple table joins across staging area + + **Example Queries:** + ```sql + -- Count rows in staging table + SELECT COUNT(*) FROM Entity; + + -- Check for nulls + SELECT * FROM Entity WHERE name IS NULL LIMIT 10; + + -- Find duplicates + SELECT identifier, COUNT(*) as cnt + FROM Entity + GROUP BY identifier + HAVING COUNT(*) > 1; + + -- Join across tables + SELECT e.name, COUNT(t.id) as transaction_count + FROM Entity e + LEFT JOIN Transaction t ON e.identifier = t.entity_id + GROUP BY e.name + ORDER BY transaction_count DESC; + ``` + + **Limits:** + - Query timeout: 30 seconds + - Result limit: 10,000 rows (use LIMIT clause) + - Read-only: No INSERT, UPDATE, DELETE + - User's tables only: Cannot query other users' data + + **Shared Repositories:** + Shared repositories (SEC, etc.) do not allow direct SQL queries. + Use the graph query endpoint instead: `POST /v1/graphs/{graph_id}/query` + + **Note:** + Staging table queries are included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + body (TableQueryRequest): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, ErrorResponse, HTTPValidationError, TableQueryResponse]] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + body=body, + token=token, + authorization=authorization, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + graph_id: str, + *, + client: AuthenticatedClient, + body: TableQueryRequest, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Optional[Union[Any, ErrorResponse, HTTPValidationError, TableQueryResponse]]: + """Query Staging Tables with SQL + + Execute SQL queries on DuckDB staging tables for data inspection and validation. + + **Purpose:** + Query raw staging data directly with SQL before ingestion into the graph database. + Useful for data quality checks, validation, and exploratory analysis. + + **Use Cases:** + - Validate data quality before graph ingestion + - Inspect row-level data for debugging + - Run analytics on staging tables + - Check for duplicates, nulls, or data issues + - Preview data transformations + + **Workflow:** + 1. Upload data files via `POST /tables/{table_name}/files` + 2. Query staging tables to validate: `POST /tables/query` + 3. Fix any data issues by re-uploading + 4. Ingest validated data: `POST /tables/ingest` + + **Supported SQL:** + - Full DuckDB SQL syntax + - SELECT, JOIN, WHERE, GROUP BY, ORDER BY + - Aggregations, window functions, CTEs + - Multiple table joins across staging area + + **Example Queries:** + ```sql + -- Count rows in staging table + SELECT COUNT(*) FROM Entity; + + -- Check for nulls + SELECT * FROM Entity WHERE name IS NULL LIMIT 10; + + -- Find duplicates + SELECT identifier, COUNT(*) as cnt + FROM Entity + GROUP BY identifier + HAVING COUNT(*) > 1; + + -- Join across tables + SELECT e.name, COUNT(t.id) as transaction_count + FROM Entity e + LEFT JOIN Transaction t ON e.identifier = t.entity_id + GROUP BY e.name + ORDER BY transaction_count DESC; + ``` + + **Limits:** + - Query timeout: 30 seconds + - Result limit: 10,000 rows (use LIMIT clause) + - Read-only: No INSERT, UPDATE, DELETE + - User's tables only: Cannot query other users' data + + **Shared Repositories:** + Shared repositories (SEC, etc.) do not allow direct SQL queries. + Use the graph query endpoint instead: `POST /v1/graphs/{graph_id}/query` + + **Note:** + Staging table queries are included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + body (TableQueryRequest): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, ErrorResponse, HTTPValidationError, TableQueryResponse] + """ + + return sync_detailed( + graph_id=graph_id, + client=client, + body=body, + token=token, + authorization=authorization, + ).parsed + + +async def asyncio_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + body: TableQueryRequest, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Response[Union[Any, ErrorResponse, HTTPValidationError, TableQueryResponse]]: + """Query Staging Tables with SQL + + Execute SQL queries on DuckDB staging tables for data inspection and validation. + + **Purpose:** + Query raw staging data directly with SQL before ingestion into the graph database. + Useful for data quality checks, validation, and exploratory analysis. + + **Use Cases:** + - Validate data quality before graph ingestion + - Inspect row-level data for debugging + - Run analytics on staging tables + - Check for duplicates, nulls, or data issues + - Preview data transformations + + **Workflow:** + 1. Upload data files via `POST /tables/{table_name}/files` + 2. Query staging tables to validate: `POST /tables/query` + 3. Fix any data issues by re-uploading + 4. Ingest validated data: `POST /tables/ingest` + + **Supported SQL:** + - Full DuckDB SQL syntax + - SELECT, JOIN, WHERE, GROUP BY, ORDER BY + - Aggregations, window functions, CTEs + - Multiple table joins across staging area + + **Example Queries:** + ```sql + -- Count rows in staging table + SELECT COUNT(*) FROM Entity; + + -- Check for nulls + SELECT * FROM Entity WHERE name IS NULL LIMIT 10; + + -- Find duplicates + SELECT identifier, COUNT(*) as cnt + FROM Entity + GROUP BY identifier + HAVING COUNT(*) > 1; + + -- Join across tables + SELECT e.name, COUNT(t.id) as transaction_count + FROM Entity e + LEFT JOIN Transaction t ON e.identifier = t.entity_id + GROUP BY e.name + ORDER BY transaction_count DESC; + ``` + + **Limits:** + - Query timeout: 30 seconds + - Result limit: 10,000 rows (use LIMIT clause) + - Read-only: No INSERT, UPDATE, DELETE + - User's tables only: Cannot query other users' data + + **Shared Repositories:** + Shared repositories (SEC, etc.) do not allow direct SQL queries. + Use the graph query endpoint instead: `POST /v1/graphs/{graph_id}/query` + + **Note:** + Staging table queries are included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + body (TableQueryRequest): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, ErrorResponse, HTTPValidationError, TableQueryResponse]] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + body=body, + token=token, + authorization=authorization, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + graph_id: str, + *, + client: AuthenticatedClient, + body: TableQueryRequest, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Optional[Union[Any, ErrorResponse, HTTPValidationError, TableQueryResponse]]: + """Query Staging Tables with SQL + + Execute SQL queries on DuckDB staging tables for data inspection and validation. + + **Purpose:** + Query raw staging data directly with SQL before ingestion into the graph database. + Useful for data quality checks, validation, and exploratory analysis. + + **Use Cases:** + - Validate data quality before graph ingestion + - Inspect row-level data for debugging + - Run analytics on staging tables + - Check for duplicates, nulls, or data issues + - Preview data transformations + + **Workflow:** + 1. Upload data files via `POST /tables/{table_name}/files` + 2. Query staging tables to validate: `POST /tables/query` + 3. Fix any data issues by re-uploading + 4. Ingest validated data: `POST /tables/ingest` + + **Supported SQL:** + - Full DuckDB SQL syntax + - SELECT, JOIN, WHERE, GROUP BY, ORDER BY + - Aggregations, window functions, CTEs + - Multiple table joins across staging area + + **Example Queries:** + ```sql + -- Count rows in staging table + SELECT COUNT(*) FROM Entity; + + -- Check for nulls + SELECT * FROM Entity WHERE name IS NULL LIMIT 10; + + -- Find duplicates + SELECT identifier, COUNT(*) as cnt + FROM Entity + GROUP BY identifier + HAVING COUNT(*) > 1; + + -- Join across tables + SELECT e.name, COUNT(t.id) as transaction_count + FROM Entity e + LEFT JOIN Transaction t ON e.identifier = t.entity_id + GROUP BY e.name + ORDER BY transaction_count DESC; + ``` + + **Limits:** + - Query timeout: 30 seconds + - Result limit: 10,000 rows (use LIMIT clause) + - Read-only: No INSERT, UPDATE, DELETE + - User's tables only: Cannot query other users' data + + **Shared Repositories:** + Shared repositories (SEC, etc.) do not allow direct SQL queries. + Use the graph query endpoint instead: `POST /v1/graphs/{graph_id}/query` + + **Note:** + Staging table queries are included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + body (TableQueryRequest): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, ErrorResponse, HTTPValidationError, TableQueryResponse] + """ + + return ( + await asyncio_detailed( + graph_id=graph_id, + client=client, + body=body, + token=token, + authorization=authorization, + ) + ).parsed diff --git a/robosystems_client/api/tables/query_tables_v1_graphs_graph_id_tables_query_post.py b/robosystems_client/api/tables/query_tables_v1_graphs_graph_id_tables_query_post.py deleted file mode 100644 index 4078d3c..0000000 --- a/robosystems_client/api/tables/query_tables_v1_graphs_graph_id_tables_query_post.py +++ /dev/null @@ -1,247 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union, cast - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.error_response import ErrorResponse -from ...models.http_validation_error import HTTPValidationError -from ...models.table_query_request import TableQueryRequest -from ...models.table_query_response import TableQueryResponse -from ...types import UNSET, Response, Unset - - -def _get_kwargs( - graph_id: str, - *, - body: TableQueryRequest, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - if not isinstance(authorization, Unset): - headers["authorization"] = authorization - - params: dict[str, Any] = {} - - json_token: Union[None, Unset, str] - if isinstance(token, Unset): - json_token = UNSET - else: - json_token = token - params["token"] = json_token - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "post", - "url": f"/v1/graphs/{graph_id}/tables/query", - "params": params, - } - - _kwargs["json"] = body.to_dict() - - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[Any, ErrorResponse, HTTPValidationError, TableQueryResponse]]: - if response.status_code == 200: - response_200 = TableQueryResponse.from_dict(response.json()) - - return response_200 - - if response.status_code == 400: - response_400 = ErrorResponse.from_dict(response.json()) - - return response_400 - - if response.status_code == 401: - response_401 = cast(Any, None) - return response_401 - - if response.status_code == 403: - response_403 = ErrorResponse.from_dict(response.json()) - - return response_403 - - if response.status_code == 404: - response_404 = ErrorResponse.from_dict(response.json()) - - return response_404 - - if response.status_code == 422: - response_422 = HTTPValidationError.from_dict(response.json()) - - return response_422 - - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[Any, ErrorResponse, HTTPValidationError, TableQueryResponse]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - graph_id: str, - *, - client: AuthenticatedClient, - body: TableQueryRequest, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Response[Union[Any, ErrorResponse, HTTPValidationError, TableQueryResponse]]: - """Query Staging Tables with SQL - - Execute SQL queries on DuckDB staging tables - - Args: - graph_id (str): Graph database identifier - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - body (TableQueryRequest): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, ErrorResponse, HTTPValidationError, TableQueryResponse]] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - body=body, - token=token, - authorization=authorization, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - graph_id: str, - *, - client: AuthenticatedClient, - body: TableQueryRequest, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Optional[Union[Any, ErrorResponse, HTTPValidationError, TableQueryResponse]]: - """Query Staging Tables with SQL - - Execute SQL queries on DuckDB staging tables - - Args: - graph_id (str): Graph database identifier - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - body (TableQueryRequest): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, ErrorResponse, HTTPValidationError, TableQueryResponse] - """ - - return sync_detailed( - graph_id=graph_id, - client=client, - body=body, - token=token, - authorization=authorization, - ).parsed - - -async def asyncio_detailed( - graph_id: str, - *, - client: AuthenticatedClient, - body: TableQueryRequest, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Response[Union[Any, ErrorResponse, HTTPValidationError, TableQueryResponse]]: - """Query Staging Tables with SQL - - Execute SQL queries on DuckDB staging tables - - Args: - graph_id (str): Graph database identifier - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - body (TableQueryRequest): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, ErrorResponse, HTTPValidationError, TableQueryResponse]] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - body=body, - token=token, - authorization=authorization, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - graph_id: str, - *, - client: AuthenticatedClient, - body: TableQueryRequest, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Optional[Union[Any, ErrorResponse, HTTPValidationError, TableQueryResponse]]: - """Query Staging Tables with SQL - - Execute SQL queries on DuckDB staging tables - - Args: - graph_id (str): Graph database identifier - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - body (TableQueryRequest): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, ErrorResponse, HTTPValidationError, TableQueryResponse] - """ - - return ( - await asyncio_detailed( - graph_id=graph_id, - client=client, - body=body, - token=token, - authorization=authorization, - ) - ).parsed diff --git a/robosystems_client/api/tables/update_file_status.py b/robosystems_client/api/tables/update_file_status.py new file mode 100644 index 0000000..a0d0ad7 --- /dev/null +++ b/robosystems_client/api/tables/update_file_status.py @@ -0,0 +1,539 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error_response import ErrorResponse +from ...models.file_status_update import FileStatusUpdate +from ...models.http_validation_error import HTTPValidationError +from ...models.update_file_status_response_updatefilestatus import ( + UpdateFileStatusResponseUpdatefilestatus, +) +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + graph_id: str, + file_id: str, + *, + body: FileStatusUpdate, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + if not isinstance(authorization, Unset): + headers["authorization"] = authorization + + params: dict[str, Any] = {} + + json_token: Union[None, Unset, str] + if isinstance(token, Unset): + json_token = UNSET + else: + json_token = token + params["token"] = json_token + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "patch", + "url": f"/v1/graphs/{graph_id}/tables/files/{file_id}", + "params": params, + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[ + Union[ + Any, ErrorResponse, HTTPValidationError, UpdateFileStatusResponseUpdatefilestatus + ] +]: + if response.status_code == 200: + response_200 = UpdateFileStatusResponseUpdatefilestatus.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = ErrorResponse.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ErrorResponse.from_dict(response.json()) + + return response_404 + + if response.status_code == 413: + response_413 = ErrorResponse.from_dict(response.json()) + + return response_413 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if response.status_code == 500: + response_500 = cast(Any, None) + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[ + Union[ + Any, ErrorResponse, HTTPValidationError, UpdateFileStatusResponseUpdatefilestatus + ] +]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + graph_id: str, + file_id: str, + *, + client: AuthenticatedClient, + body: FileStatusUpdate, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Response[ + Union[ + Any, ErrorResponse, HTTPValidationError, UpdateFileStatusResponseUpdatefilestatus + ] +]: + r""" Update File Upload Status + + Update file status after upload completes. + + **Purpose:** + Mark files as uploaded after successful S3 upload. The backend validates + the file, calculates size and row count, enforces storage limits, and + registers the DuckDB table for queries. + + **Status Values:** + - `uploaded`: File successfully uploaded to S3 (triggers validation) + - `disabled`: Exclude file from ingestion + - `archived`: Soft delete file + + **What Happens on 'uploaded' Status:** + 1. Verify file exists in S3 + 2. Calculate actual file size + 3. Enforce tier storage limits + 4. Calculate or estimate row count + 5. Update table statistics + 6. Register DuckDB external table + 7. File ready for ingestion + + **Row Count Calculation:** + - **Parquet**: Exact count from file metadata + - **CSV**: Count rows (minus header) + - **JSON**: Count array elements + - **Fallback**: Estimate from file size if reading fails + + **Storage Limits:** + Enforced per subscription tier: + - Prevents uploads exceeding tier limit + - Returns HTTP 413 if limit exceeded + - Check current usage before large uploads + + **Example Response:** + ```json + { + \"status\": \"success\", + \"file_id\": \"f123\", + \"upload_status\": \"uploaded\", + \"file_size_bytes\": 1048576, + \"row_count\": 5000, + \"message\": \"File validated and ready for ingestion\" + } + ``` + + **Example Usage:** + ```bash + # After uploading file to S3 presigned URL + curl -X PATCH \"https://api.robosystems.ai/v1/graphs/kg123/tables/files/f123\" \ + -H \"Authorization: Bearer YOUR_TOKEN\" \ + -H \"Content-Type: application/json\" \ + -d '{\"status\": \"uploaded\"}' + ``` + + **Tips:** + - Always call this after S3 upload completes + - Check response for actual row count + - Storage limit errors (413) mean tier upgrade needed + - DuckDB registration failures are non-fatal (retried later) + + **Note:** + Status updates are included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + file_id (str): File identifier + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + body (FileStatusUpdate): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, ErrorResponse, HTTPValidationError, UpdateFileStatusResponseUpdatefilestatus]] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + file_id=file_id, + body=body, + token=token, + authorization=authorization, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + graph_id: str, + file_id: str, + *, + client: AuthenticatedClient, + body: FileStatusUpdate, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Optional[ + Union[ + Any, ErrorResponse, HTTPValidationError, UpdateFileStatusResponseUpdatefilestatus + ] +]: + r""" Update File Upload Status + + Update file status after upload completes. + + **Purpose:** + Mark files as uploaded after successful S3 upload. The backend validates + the file, calculates size and row count, enforces storage limits, and + registers the DuckDB table for queries. + + **Status Values:** + - `uploaded`: File successfully uploaded to S3 (triggers validation) + - `disabled`: Exclude file from ingestion + - `archived`: Soft delete file + + **What Happens on 'uploaded' Status:** + 1. Verify file exists in S3 + 2. Calculate actual file size + 3. Enforce tier storage limits + 4. Calculate or estimate row count + 5. Update table statistics + 6. Register DuckDB external table + 7. File ready for ingestion + + **Row Count Calculation:** + - **Parquet**: Exact count from file metadata + - **CSV**: Count rows (minus header) + - **JSON**: Count array elements + - **Fallback**: Estimate from file size if reading fails + + **Storage Limits:** + Enforced per subscription tier: + - Prevents uploads exceeding tier limit + - Returns HTTP 413 if limit exceeded + - Check current usage before large uploads + + **Example Response:** + ```json + { + \"status\": \"success\", + \"file_id\": \"f123\", + \"upload_status\": \"uploaded\", + \"file_size_bytes\": 1048576, + \"row_count\": 5000, + \"message\": \"File validated and ready for ingestion\" + } + ``` + + **Example Usage:** + ```bash + # After uploading file to S3 presigned URL + curl -X PATCH \"https://api.robosystems.ai/v1/graphs/kg123/tables/files/f123\" \ + -H \"Authorization: Bearer YOUR_TOKEN\" \ + -H \"Content-Type: application/json\" \ + -d '{\"status\": \"uploaded\"}' + ``` + + **Tips:** + - Always call this after S3 upload completes + - Check response for actual row count + - Storage limit errors (413) mean tier upgrade needed + - DuckDB registration failures are non-fatal (retried later) + + **Note:** + Status updates are included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + file_id (str): File identifier + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + body (FileStatusUpdate): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, ErrorResponse, HTTPValidationError, UpdateFileStatusResponseUpdatefilestatus] + """ + + return sync_detailed( + graph_id=graph_id, + file_id=file_id, + client=client, + body=body, + token=token, + authorization=authorization, + ).parsed + + +async def asyncio_detailed( + graph_id: str, + file_id: str, + *, + client: AuthenticatedClient, + body: FileStatusUpdate, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Response[ + Union[ + Any, ErrorResponse, HTTPValidationError, UpdateFileStatusResponseUpdatefilestatus + ] +]: + r""" Update File Upload Status + + Update file status after upload completes. + + **Purpose:** + Mark files as uploaded after successful S3 upload. The backend validates + the file, calculates size and row count, enforces storage limits, and + registers the DuckDB table for queries. + + **Status Values:** + - `uploaded`: File successfully uploaded to S3 (triggers validation) + - `disabled`: Exclude file from ingestion + - `archived`: Soft delete file + + **What Happens on 'uploaded' Status:** + 1. Verify file exists in S3 + 2. Calculate actual file size + 3. Enforce tier storage limits + 4. Calculate or estimate row count + 5. Update table statistics + 6. Register DuckDB external table + 7. File ready for ingestion + + **Row Count Calculation:** + - **Parquet**: Exact count from file metadata + - **CSV**: Count rows (minus header) + - **JSON**: Count array elements + - **Fallback**: Estimate from file size if reading fails + + **Storage Limits:** + Enforced per subscription tier: + - Prevents uploads exceeding tier limit + - Returns HTTP 413 if limit exceeded + - Check current usage before large uploads + + **Example Response:** + ```json + { + \"status\": \"success\", + \"file_id\": \"f123\", + \"upload_status\": \"uploaded\", + \"file_size_bytes\": 1048576, + \"row_count\": 5000, + \"message\": \"File validated and ready for ingestion\" + } + ``` + + **Example Usage:** + ```bash + # After uploading file to S3 presigned URL + curl -X PATCH \"https://api.robosystems.ai/v1/graphs/kg123/tables/files/f123\" \ + -H \"Authorization: Bearer YOUR_TOKEN\" \ + -H \"Content-Type: application/json\" \ + -d '{\"status\": \"uploaded\"}' + ``` + + **Tips:** + - Always call this after S3 upload completes + - Check response for actual row count + - Storage limit errors (413) mean tier upgrade needed + - DuckDB registration failures are non-fatal (retried later) + + **Note:** + Status updates are included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + file_id (str): File identifier + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + body (FileStatusUpdate): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, ErrorResponse, HTTPValidationError, UpdateFileStatusResponseUpdatefilestatus]] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + file_id=file_id, + body=body, + token=token, + authorization=authorization, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + graph_id: str, + file_id: str, + *, + client: AuthenticatedClient, + body: FileStatusUpdate, + token: Union[None, Unset, str] = UNSET, + authorization: Union[None, Unset, str] = UNSET, +) -> Optional[ + Union[ + Any, ErrorResponse, HTTPValidationError, UpdateFileStatusResponseUpdatefilestatus + ] +]: + r""" Update File Upload Status + + Update file status after upload completes. + + **Purpose:** + Mark files as uploaded after successful S3 upload. The backend validates + the file, calculates size and row count, enforces storage limits, and + registers the DuckDB table for queries. + + **Status Values:** + - `uploaded`: File successfully uploaded to S3 (triggers validation) + - `disabled`: Exclude file from ingestion + - `archived`: Soft delete file + + **What Happens on 'uploaded' Status:** + 1. Verify file exists in S3 + 2. Calculate actual file size + 3. Enforce tier storage limits + 4. Calculate or estimate row count + 5. Update table statistics + 6. Register DuckDB external table + 7. File ready for ingestion + + **Row Count Calculation:** + - **Parquet**: Exact count from file metadata + - **CSV**: Count rows (minus header) + - **JSON**: Count array elements + - **Fallback**: Estimate from file size if reading fails + + **Storage Limits:** + Enforced per subscription tier: + - Prevents uploads exceeding tier limit + - Returns HTTP 413 if limit exceeded + - Check current usage before large uploads + + **Example Response:** + ```json + { + \"status\": \"success\", + \"file_id\": \"f123\", + \"upload_status\": \"uploaded\", + \"file_size_bytes\": 1048576, + \"row_count\": 5000, + \"message\": \"File validated and ready for ingestion\" + } + ``` + + **Example Usage:** + ```bash + # After uploading file to S3 presigned URL + curl -X PATCH \"https://api.robosystems.ai/v1/graphs/kg123/tables/files/f123\" \ + -H \"Authorization: Bearer YOUR_TOKEN\" \ + -H \"Content-Type: application/json\" \ + -d '{\"status\": \"uploaded\"}' + ``` + + **Tips:** + - Always call this after S3 upload completes + - Check response for actual row count + - Storage limit errors (413) mean tier upgrade needed + - DuckDB registration failures are non-fatal (retried later) + + **Note:** + Status updates are included - no credit consumption. + + Args: + graph_id (str): Graph database identifier + file_id (str): File identifier + token (Union[None, Unset, str]): JWT token for SSE authentication + authorization (Union[None, Unset, str]): + body (FileStatusUpdate): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, ErrorResponse, HTTPValidationError, UpdateFileStatusResponseUpdatefilestatus] + """ + + return ( + await asyncio_detailed( + graph_id=graph_id, + file_id=file_id, + client=client, + body=body, + token=token, + authorization=authorization, + ) + ).parsed diff --git a/robosystems_client/api/tables/update_file_v1_graphs_graph_id_tables_files_file_id_patch.py b/robosystems_client/api/tables/update_file_v1_graphs_graph_id_tables_files_file_id_patch.py deleted file mode 100644 index b2a7ebd..0000000 --- a/robosystems_client/api/tables/update_file_v1_graphs_graph_id_tables_files_file_id_patch.py +++ /dev/null @@ -1,306 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union, cast - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.error_response import ErrorResponse -from ...models.file_update_request import FileUpdateRequest -from ...models.http_validation_error import HTTPValidationError -from ...models.update_file_v1_graphs_graph_id_tables_files_file_id_patch_response_update_file_v1_graphs_graph_id_tables_files_file_id_patch import ( - UpdateFileV1GraphsGraphIdTablesFilesFileIdPatchResponseUpdateFileV1GraphsGraphIdTablesFilesFileIdPatch, -) -from ...types import UNSET, Response, Unset - - -def _get_kwargs( - graph_id: str, - file_id: str, - *, - body: FileUpdateRequest, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - if not isinstance(authorization, Unset): - headers["authorization"] = authorization - - params: dict[str, Any] = {} - - json_token: Union[None, Unset, str] - if isinstance(token, Unset): - json_token = UNSET - else: - json_token = token - params["token"] = json_token - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "patch", - "url": f"/v1/graphs/{graph_id}/tables/files/{file_id}", - "params": params, - } - - _kwargs["json"] = body.to_dict() - - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[ - Union[ - Any, - ErrorResponse, - HTTPValidationError, - UpdateFileV1GraphsGraphIdTablesFilesFileIdPatchResponseUpdateFileV1GraphsGraphIdTablesFilesFileIdPatch, - ] -]: - if response.status_code == 200: - response_200 = UpdateFileV1GraphsGraphIdTablesFilesFileIdPatchResponseUpdateFileV1GraphsGraphIdTablesFilesFileIdPatch.from_dict( - response.json() - ) - - return response_200 - - if response.status_code == 400: - response_400 = ErrorResponse.from_dict(response.json()) - - return response_400 - - if response.status_code == 401: - response_401 = cast(Any, None) - return response_401 - - if response.status_code == 403: - response_403 = ErrorResponse.from_dict(response.json()) - - return response_403 - - if response.status_code == 404: - response_404 = ErrorResponse.from_dict(response.json()) - - return response_404 - - if response.status_code == 422: - response_422 = HTTPValidationError.from_dict(response.json()) - - return response_422 - - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[ - Union[ - Any, - ErrorResponse, - HTTPValidationError, - UpdateFileV1GraphsGraphIdTablesFilesFileIdPatchResponseUpdateFileV1GraphsGraphIdTablesFilesFileIdPatch, - ] -]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - graph_id: str, - file_id: str, - *, - client: AuthenticatedClient, - body: FileUpdateRequest, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Response[ - Union[ - Any, - ErrorResponse, - HTTPValidationError, - UpdateFileV1GraphsGraphIdTablesFilesFileIdPatchResponseUpdateFileV1GraphsGraphIdTablesFilesFileIdPatch, - ] -]: - """Update File - - Update file metadata after upload (size, row count). Marks file as completed. - - Args: - graph_id (str): Graph database identifier - file_id (str): File identifier - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - body (FileUpdateRequest): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, ErrorResponse, HTTPValidationError, UpdateFileV1GraphsGraphIdTablesFilesFileIdPatchResponseUpdateFileV1GraphsGraphIdTablesFilesFileIdPatch]] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - file_id=file_id, - body=body, - token=token, - authorization=authorization, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - graph_id: str, - file_id: str, - *, - client: AuthenticatedClient, - body: FileUpdateRequest, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Optional[ - Union[ - Any, - ErrorResponse, - HTTPValidationError, - UpdateFileV1GraphsGraphIdTablesFilesFileIdPatchResponseUpdateFileV1GraphsGraphIdTablesFilesFileIdPatch, - ] -]: - """Update File - - Update file metadata after upload (size, row count). Marks file as completed. - - Args: - graph_id (str): Graph database identifier - file_id (str): File identifier - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - body (FileUpdateRequest): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, ErrorResponse, HTTPValidationError, UpdateFileV1GraphsGraphIdTablesFilesFileIdPatchResponseUpdateFileV1GraphsGraphIdTablesFilesFileIdPatch] - """ - - return sync_detailed( - graph_id=graph_id, - file_id=file_id, - client=client, - body=body, - token=token, - authorization=authorization, - ).parsed - - -async def asyncio_detailed( - graph_id: str, - file_id: str, - *, - client: AuthenticatedClient, - body: FileUpdateRequest, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Response[ - Union[ - Any, - ErrorResponse, - HTTPValidationError, - UpdateFileV1GraphsGraphIdTablesFilesFileIdPatchResponseUpdateFileV1GraphsGraphIdTablesFilesFileIdPatch, - ] -]: - """Update File - - Update file metadata after upload (size, row count). Marks file as completed. - - Args: - graph_id (str): Graph database identifier - file_id (str): File identifier - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - body (FileUpdateRequest): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, ErrorResponse, HTTPValidationError, UpdateFileV1GraphsGraphIdTablesFilesFileIdPatchResponseUpdateFileV1GraphsGraphIdTablesFilesFileIdPatch]] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - file_id=file_id, - body=body, - token=token, - authorization=authorization, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - graph_id: str, - file_id: str, - *, - client: AuthenticatedClient, - body: FileUpdateRequest, - token: Union[None, Unset, str] = UNSET, - authorization: Union[None, Unset, str] = UNSET, -) -> Optional[ - Union[ - Any, - ErrorResponse, - HTTPValidationError, - UpdateFileV1GraphsGraphIdTablesFilesFileIdPatchResponseUpdateFileV1GraphsGraphIdTablesFilesFileIdPatch, - ] -]: - """Update File - - Update file metadata after upload (size, row count). Marks file as completed. - - Args: - graph_id (str): Graph database identifier - file_id (str): File identifier - token (Union[None, Unset, str]): JWT token for SSE authentication - authorization (Union[None, Unset, str]): - body (FileUpdateRequest): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, ErrorResponse, HTTPValidationError, UpdateFileV1GraphsGraphIdTablesFilesFileIdPatchResponseUpdateFileV1GraphsGraphIdTablesFilesFileIdPatch] - """ - - return ( - await asyncio_detailed( - graph_id=graph_id, - file_id=file_id, - client=client, - body=body, - token=token, - authorization=authorization, - ) - ).parsed diff --git a/robosystems_client/extensions/graph_client.py b/robosystems_client/extensions/graph_client.py index a40a2b9..5320a65 100644 --- a/robosystems_client/extensions/graph_client.py +++ b/robosystems_client/extensions/graph_client.py @@ -58,6 +58,7 @@ def create_graph_and_wait( self, metadata: GraphMetadata, initial_entity: Optional[InitialEntityData] = None, + create_entity: bool = True, timeout: int = 60, poll_interval: int = 2, on_progress: Optional[Callable[[str], None]] = None, @@ -68,6 +69,9 @@ def create_graph_and_wait( Args: metadata: Graph metadata initial_entity: Optional initial entity data + create_entity: Whether to create the entity node and upload initial data. + Only applies when initial_entity is provided. Set to False to create + graph without populating entity data (useful for file-based ingestion). timeout: Maximum time to wait in seconds poll_interval: Time between status checks in seconds on_progress: Callback for progress updates @@ -121,6 +125,7 @@ def create_graph_and_wait( graph_create = CreateGraphRequest( metadata=api_metadata, initial_entity=initial_entity_dict, + create_entity=create_entity, ) if on_progress: diff --git a/robosystems_client/extensions/table_ingest_client.py b/robosystems_client/extensions/table_ingest_client.py index e2d8cbe..d5f839f 100644 --- a/robosystems_client/extensions/table_ingest_client.py +++ b/robosystems_client/extensions/table_ingest_client.py @@ -11,20 +11,20 @@ import logging import httpx -from ..api.tables.get_upload_url_v1_graphs_graph_id_tables_table_name_files_post import ( +from ..api.tables.get_upload_url import ( sync_detailed as get_upload_url, ) -from ..api.tables.update_file_v1_graphs_graph_id_tables_files_file_id_patch import ( - sync_detailed as update_file, +from ..api.tables.update_file_status import ( + sync_detailed as update_file_status, ) -from ..api.tables.list_tables_v1_graphs_graph_id_tables_get import ( +from ..api.tables.list_tables import ( sync_detailed as list_tables, ) -from ..api.tables.ingest_tables_v1_graphs_graph_id_tables_ingest_post import ( +from ..api.tables.ingest_tables import ( sync_detailed as ingest_tables, ) from ..models.file_upload_request import FileUploadRequest -from ..models.file_update_request import FileUpdateRequest +from ..models.file_status_update import FileStatusUpdate from ..models.bulk_ingest_request import BulkIngestRequest logger = logging.getLogger(__name__) @@ -95,7 +95,7 @@ def upload_parquet_file( This method handles the complete 3-step upload process: 1. Get presigned upload URL 2. Upload file to S3 - 3. Update file metadata + 3. Mark file as 'uploaded' (backend validates, calculates size/row count) Args: graph_id: The graph ID @@ -104,7 +104,7 @@ def upload_parquet_file( options: Upload options Returns: - UploadResult with upload details + UploadResult with upload details (size/row count calculated by backend) """ if options is None: options = UploadOptions() @@ -216,12 +216,10 @@ def upload_parquet_file( # BinaryIO or file-like object file_or_buffer.seek(0) file_content = file_or_buffer.read() - file_size = len(file_content) else: # Read from file path with open(file_path, "rb") as f: file_content = f.read() - file_size = len(file_content) s3_response = self._http_client.put( upload_url, @@ -230,54 +228,47 @@ def upload_parquet_file( ) s3_response.raise_for_status() - # Step 3: Get row count and update file metadata + # Step 3: Mark file as uploaded (backend validates and calculates size/row count) if options.on_progress: - options.on_progress(f"Updating file metadata for {file_name}...") + options.on_progress(f"Marking {file_name} as uploaded...") - try: - import pyarrow.parquet as pq - - if is_buffer: - # Read from buffer for row count - if hasattr(file_or_buffer, "seek"): - file_or_buffer.seek(0) - parquet_table = pq.read_table(file_or_buffer) - else: - # Read from file path - parquet_table = pq.read_table(file_path) - - row_count = parquet_table.num_rows - except ImportError: - logger.warning( - "pyarrow not installed, row count will be estimated from file size" - ) - # Rough estimate: ~100 bytes per row for typical data - row_count = file_size // 100 - - metadata_update = FileUpdateRequest( - file_size_bytes=file_size, row_count=row_count - ) + status_update = FileStatusUpdate(status="uploaded") kwargs = { "graph_id": graph_id, "file_id": file_id, "client": client, - "body": metadata_update, + "body": status_update, } - update_response = update_file(**kwargs) + update_response = update_file_status(**kwargs) if not update_response.parsed: + logger.error( + f"No parsed response from update_file_status. Status code: {update_response.status_code}" + ) return UploadResult( file_id=file_id, - file_size=file_size, - row_count=row_count, + file_size=0, + row_count=0, table_name=table_name, file_name=file_name, success=False, - error="Failed to update file metadata", + error="Failed to complete file upload", ) + response_data = update_response.parsed + + if isinstance(response_data, dict): + file_size = response_data.get("file_size_bytes", 0) + row_count = response_data.get("row_count", 0) + elif hasattr(response_data, "additional_properties"): + file_size = response_data.additional_properties.get("file_size_bytes", 0) + row_count = response_data.additional_properties.get("row_count", 0) + else: + file_size = getattr(response_data, "file_size_bytes", 0) + row_count = getattr(response_data, "row_count", 0) + if options.on_progress: options.on_progress( f"✅ Uploaded {file_name} ({file_size:,} bytes, {row_count:,} rows)" diff --git a/robosystems_client/models/__init__.py b/robosystems_client/models/__init__.py index 7dac8b8..4c40b7a 100644 --- a/robosystems_client/models/__init__.py +++ b/robosystems_client/models/__init__.py @@ -75,9 +75,7 @@ from .cypher_query_request_parameters_type_0 import CypherQueryRequestParametersType0 from .database_health_response import DatabaseHealthResponse from .database_info_response import DatabaseInfoResponse -from .delete_file_v1_graphs_graph_id_tables_files_file_id_delete_response_delete_file_v1_graphs_graph_id_tables_files_file_id_delete import ( - DeleteFileV1GraphsGraphIdTablesFilesFileIdDeleteResponseDeleteFileV1GraphsGraphIdTablesFilesFileIdDelete, -) +from .delete_file_response import DeleteFileResponse from .delete_subgraph_request import DeleteSubgraphRequest from .delete_subgraph_response import DeleteSubgraphResponse from .detailed_transactions_response import DetailedTransactionsResponse @@ -93,7 +91,8 @@ from .error_response import ErrorResponse from .exchange_token_request import ExchangeTokenRequest from .exchange_token_request_metadata_type_0 import ExchangeTokenRequestMetadataType0 -from .file_update_request import FileUpdateRequest +from .file_info import FileInfo +from .file_status_update import FileStatusUpdate from .file_upload_request import FileUploadRequest from .file_upload_response import FileUploadResponse from .forgot_password_request import ForgotPasswordRequest @@ -115,9 +114,7 @@ from .get_current_graph_bill_response_getcurrentgraphbill import ( GetCurrentGraphBillResponseGetcurrentgraphbill, ) -from .get_file_info_v1_graphs_graph_id_tables_files_file_id_get_response_get_file_info_v1_graphs_graph_id_tables_files_file_id_get import ( - GetFileInfoV1GraphsGraphIdTablesFilesFileIdGetResponseGetFileInfoV1GraphsGraphIdTablesFilesFileIdGet, -) +from .get_file_info_response import GetFileInfoResponse from .get_graph_billing_history_response_getgraphbillinghistory import ( GetGraphBillingHistoryResponseGetgraphbillinghistory, ) @@ -164,9 +161,7 @@ from .link_token_request_provider_type_0 import LinkTokenRequestProviderType0 from .list_connections_provider_type_0 import ListConnectionsProviderType0 from .list_subgraphs_response import ListSubgraphsResponse -from .list_table_files_v1_graphs_graph_id_tables_table_name_files_get_response_list_table_files_v1_graphs_graph_id_tables_table_name_files_get import ( - ListTableFilesV1GraphsGraphIdTablesTableNameFilesGetResponseListTableFilesV1GraphsGraphIdTablesTableNameFilesGet, -) +from .list_table_files_response import ListTableFilesResponse from .login_request import LoginRequest from .logout_user_response_logoutuser import LogoutUserResponseLogoutuser from .mcp_tool_call import MCPToolCall @@ -249,8 +244,8 @@ from .tier_upgrade_request import TierUpgradeRequest from .transaction_summary_response import TransactionSummaryResponse from .update_api_key_request import UpdateAPIKeyRequest -from .update_file_v1_graphs_graph_id_tables_files_file_id_patch_response_update_file_v1_graphs_graph_id_tables_files_file_id_patch import ( - UpdateFileV1GraphsGraphIdTablesFilesFileIdPatchResponseUpdateFileV1GraphsGraphIdTablesFilesFileIdPatch, +from .update_file_status_response_updatefilestatus import ( + UpdateFileStatusResponseUpdatefilestatus, ) from .update_password_request import UpdatePasswordRequest from .update_user_request import UpdateUserRequest @@ -339,7 +334,7 @@ "CypherQueryRequestParametersType0", "DatabaseHealthResponse", "DatabaseInfoResponse", - "DeleteFileV1GraphsGraphIdTablesFilesFileIdDeleteResponseDeleteFileV1GraphsGraphIdTablesFilesFileIdDelete", + "DeleteFileResponse", "DeleteSubgraphRequest", "DeleteSubgraphResponse", "DetailedTransactionsResponse", @@ -351,7 +346,8 @@ "ErrorResponse", "ExchangeTokenRequest", "ExchangeTokenRequestMetadataType0", - "FileUpdateRequest", + "FileInfo", + "FileStatusUpdate", "FileUploadRequest", "FileUploadResponse", "ForgotPasswordRequest", @@ -361,7 +357,7 @@ "GetBackupDownloadUrlResponseGetbackupdownloadurl", "GetCurrentAuthUserResponseGetcurrentauthuser", "GetCurrentGraphBillResponseGetcurrentgraphbill", - "GetFileInfoV1GraphsGraphIdTablesFilesFileIdGetResponseGetFileInfoV1GraphsGraphIdTablesFilesFileIdGet", + "GetFileInfoResponse", "GetGraphBillingHistoryResponseGetgraphbillinghistory", "GetGraphLimitsResponseGetgraphlimits", "GetGraphMonthlyBillResponseGetgraphmonthlybill", @@ -390,7 +386,7 @@ "LinkTokenRequestProviderType0", "ListConnectionsProviderType0", "ListSubgraphsResponse", - "ListTableFilesV1GraphsGraphIdTablesTableNameFilesGetResponseListTableFilesV1GraphsGraphIdTablesTableNameFilesGet", + "ListTableFilesResponse", "LoginRequest", "LogoutUserResponseLogoutuser", "MCPToolCall", @@ -455,7 +451,7 @@ "TierUpgradeRequest", "TransactionSummaryResponse", "UpdateAPIKeyRequest", - "UpdateFileV1GraphsGraphIdTablesFilesFileIdPatchResponseUpdateFileV1GraphsGraphIdTablesFilesFileIdPatch", + "UpdateFileStatusResponseUpdatefilestatus", "UpdatePasswordRequest", "UpdateUserRequest", "UserAnalyticsResponse", diff --git a/robosystems_client/models/create_graph_request.py b/robosystems_client/models/create_graph_request.py index ea079da..45d3b24 100644 --- a/robosystems_client/models/create_graph_request.py +++ b/robosystems_client/models/create_graph_request.py @@ -31,6 +31,9 @@ class CreateGraphRequest: custom_schema (Union['CustomSchemaDefinition', None, Unset]): Custom schema definition to apply initial_entity (Union['InitialEntityData', None, Unset]): Optional initial entity to create in the graph. If provided, creates a entity-focused graph. + create_entity (Union[Unset, bool]): Whether to create the entity node and upload initial data. Only applies when + initial_entity is provided. Set to False to create graph without populating entity data (useful for file-based + ingestion workflows). Default: True. tags (Union[Unset, list[str]]): Optional tags for organization """ @@ -38,6 +41,7 @@ class CreateGraphRequest: instance_tier: Union[Unset, str] = "kuzu-standard" custom_schema: Union["CustomSchemaDefinition", None, Unset] = UNSET initial_entity: Union["InitialEntityData", None, Unset] = UNSET + create_entity: Union[Unset, bool] = True tags: Union[Unset, list[str]] = UNSET additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) @@ -65,6 +69,8 @@ def to_dict(self) -> dict[str, Any]: else: initial_entity = self.initial_entity + create_entity = self.create_entity + tags: Union[Unset, list[str]] = UNSET if not isinstance(self.tags, Unset): tags = self.tags @@ -82,6 +88,8 @@ def to_dict(self) -> dict[str, Any]: field_dict["custom_schema"] = custom_schema if initial_entity is not UNSET: field_dict["initial_entity"] = initial_entity + if create_entity is not UNSET: + field_dict["create_entity"] = create_entity if tags is not UNSET: field_dict["tags"] = tags @@ -134,6 +142,8 @@ def _parse_initial_entity(data: object) -> Union["InitialEntityData", None, Unse initial_entity = _parse_initial_entity(d.pop("initial_entity", UNSET)) + create_entity = d.pop("create_entity", UNSET) + tags = cast(list[str], d.pop("tags", UNSET)) create_graph_request = cls( @@ -141,6 +151,7 @@ def _parse_initial_entity(data: object) -> Union["InitialEntityData", None, Unse instance_tier=instance_tier, custom_schema=custom_schema, initial_entity=initial_entity, + create_entity=create_entity, tags=tags, ) diff --git a/robosystems_client/models/delete_file_v1_graphs_graph_id_tables_files_file_id_delete_response_delete_file_v1_graphs_graph_id_tables_files_file_id_delete.py b/robosystems_client/models/delete_file_response.py similarity index 51% rename from robosystems_client/models/delete_file_v1_graphs_graph_id_tables_files_file_id_delete_response_delete_file_v1_graphs_graph_id_tables_files_file_id_delete.py rename to robosystems_client/models/delete_file_response.py index d90937b..e43e4a8 100644 --- a/robosystems_client/models/delete_file_v1_graphs_graph_id_tables_files_file_id_delete_response_delete_file_v1_graphs_graph_id_tables_files_file_id_delete.py +++ b/robosystems_client/models/delete_file_response.py @@ -4,31 +4,67 @@ from attrs import define as _attrs_define from attrs import field as _attrs_field -T = TypeVar( - "T", - bound="DeleteFileV1GraphsGraphIdTablesFilesFileIdDeleteResponseDeleteFileV1GraphsGraphIdTablesFilesFileIdDelete", -) +T = TypeVar("T", bound="DeleteFileResponse") @_attrs_define -class DeleteFileV1GraphsGraphIdTablesFilesFileIdDeleteResponseDeleteFileV1GraphsGraphIdTablesFilesFileIdDelete: - """ """ +class DeleteFileResponse: + """ + Attributes: + status (str): Deletion status + file_id (str): Deleted file ID + file_name (str): Deleted file name + message (str): Operation message + """ + status: str + file_id: str + file_name: str + message: str additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: + status = self.status + + file_id = self.file_id + + file_name = self.file_name + + message = self.message + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) + field_dict.update( + { + "status": status, + "file_id": file_id, + "file_name": file_name, + "message": message, + } + ) return field_dict @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: d = dict(src_dict) - delete_file_v1_graphs_graph_id_tables_files_file_id_delete_response_delete_file_v1_graphs_graph_id_tables_files_file_id_delete = cls() + status = d.pop("status") + + file_id = d.pop("file_id") + + file_name = d.pop("file_name") + + message = d.pop("message") + + delete_file_response = cls( + status=status, + file_id=file_id, + file_name=file_name, + message=message, + ) - delete_file_v1_graphs_graph_id_tables_files_file_id_delete_response_delete_file_v1_graphs_graph_id_tables_files_file_id_delete.additional_properties = d - return delete_file_v1_graphs_graph_id_tables_files_file_id_delete_response_delete_file_v1_graphs_graph_id_tables_files_file_id_delete + delete_file_response.additional_properties = d + return delete_file_response @property def additional_keys(self) -> list[str]: diff --git a/robosystems_client/models/file_info.py b/robosystems_client/models/file_info.py new file mode 100644 index 0000000..693b696 --- /dev/null +++ b/robosystems_client/models/file_info.py @@ -0,0 +1,169 @@ +from collections.abc import Mapping +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="FileInfo") + + +@_attrs_define +class FileInfo: + """ + Attributes: + file_id (str): Unique file identifier + file_name (str): Original file name + file_format (str): File format (parquet, csv, etc.) + size_bytes (int): File size in bytes + upload_status (str): Current upload status + upload_method (str): Upload method used + s3_key (str): S3 object key + row_count (Union[None, Unset, int]): Estimated row count + created_at (Union[None, Unset, str]): File creation timestamp + uploaded_at (Union[None, Unset, str]): File upload completion timestamp + """ + + file_id: str + file_name: str + file_format: str + size_bytes: int + upload_status: str + upload_method: str + s3_key: str + row_count: Union[None, Unset, int] = UNSET + created_at: Union[None, Unset, str] = UNSET + uploaded_at: Union[None, Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + file_id = self.file_id + + file_name = self.file_name + + file_format = self.file_format + + size_bytes = self.size_bytes + + upload_status = self.upload_status + + upload_method = self.upload_method + + s3_key = self.s3_key + + row_count: Union[None, Unset, int] + if isinstance(self.row_count, Unset): + row_count = UNSET + else: + row_count = self.row_count + + created_at: Union[None, Unset, str] + if isinstance(self.created_at, Unset): + created_at = UNSET + else: + created_at = self.created_at + + uploaded_at: Union[None, Unset, str] + if isinstance(self.uploaded_at, Unset): + uploaded_at = UNSET + else: + uploaded_at = self.uploaded_at + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "file_id": file_id, + "file_name": file_name, + "file_format": file_format, + "size_bytes": size_bytes, + "upload_status": upload_status, + "upload_method": upload_method, + "s3_key": s3_key, + } + ) + if row_count is not UNSET: + field_dict["row_count"] = row_count + if created_at is not UNSET: + field_dict["created_at"] = created_at + if uploaded_at is not UNSET: + field_dict["uploaded_at"] = uploaded_at + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + file_id = d.pop("file_id") + + file_name = d.pop("file_name") + + file_format = d.pop("file_format") + + size_bytes = d.pop("size_bytes") + + upload_status = d.pop("upload_status") + + upload_method = d.pop("upload_method") + + s3_key = d.pop("s3_key") + + def _parse_row_count(data: object) -> Union[None, Unset, int]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, int], data) + + row_count = _parse_row_count(d.pop("row_count", UNSET)) + + def _parse_created_at(data: object) -> Union[None, Unset, str]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, str], data) + + created_at = _parse_created_at(d.pop("created_at", UNSET)) + + def _parse_uploaded_at(data: object) -> Union[None, Unset, str]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, str], data) + + uploaded_at = _parse_uploaded_at(d.pop("uploaded_at", UNSET)) + + file_info = cls( + file_id=file_id, + file_name=file_name, + file_format=file_format, + size_bytes=size_bytes, + upload_status=upload_status, + upload_method=upload_method, + s3_key=s3_key, + row_count=row_count, + created_at=created_at, + uploaded_at=uploaded_at, + ) + + file_info.additional_properties = d + return file_info + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/file_status_update.py b/robosystems_client/models/file_status_update.py new file mode 100644 index 0000000..af80594 --- /dev/null +++ b/robosystems_client/models/file_status_update.py @@ -0,0 +1,41 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define + +T = TypeVar("T", bound="FileStatusUpdate") + + +@_attrs_define +class FileStatusUpdate: + """ + Attributes: + status (str): File status: 'uploaded' (ready for ingest), 'disabled' (exclude from ingest), 'archived' (soft + deleted) + """ + + status: str + + def to_dict(self) -> dict[str, Any]: + status = self.status + + field_dict: dict[str, Any] = {} + + field_dict.update( + { + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + status = d.pop("status") + + file_status_update = cls( + status=status, + ) + + return file_status_update diff --git a/robosystems_client/models/file_update_request.py b/robosystems_client/models/file_update_request.py deleted file mode 100644 index bf0a6f2..0000000 --- a/robosystems_client/models/file_update_request.py +++ /dev/null @@ -1,62 +0,0 @@ -from collections.abc import Mapping -from typing import Any, TypeVar, Union, cast - -from attrs import define as _attrs_define - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="FileUpdateRequest") - - -@_attrs_define -class FileUpdateRequest: - """ - Attributes: - file_size_bytes (int): Actual uploaded file size in bytes - row_count (Union[None, Unset, int]): Number of rows in the file - """ - - file_size_bytes: int - row_count: Union[None, Unset, int] = UNSET - - def to_dict(self) -> dict[str, Any]: - file_size_bytes = self.file_size_bytes - - row_count: Union[None, Unset, int] - if isinstance(self.row_count, Unset): - row_count = UNSET - else: - row_count = self.row_count - - field_dict: dict[str, Any] = {} - - field_dict.update( - { - "file_size_bytes": file_size_bytes, - } - ) - if row_count is not UNSET: - field_dict["row_count"] = row_count - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - file_size_bytes = d.pop("file_size_bytes") - - def _parse_row_count(data: object) -> Union[None, Unset, int]: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(Union[None, Unset, int], data) - - row_count = _parse_row_count(d.pop("row_count", UNSET)) - - file_update_request = cls( - file_size_bytes=file_size_bytes, - row_count=row_count, - ) - - return file_update_request diff --git a/robosystems_client/models/get_file_info_response.py b/robosystems_client/models/get_file_info_response.py new file mode 100644 index 0000000..7a577f0 --- /dev/null +++ b/robosystems_client/models/get_file_info_response.py @@ -0,0 +1,205 @@ +from collections.abc import Mapping +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="GetFileInfoResponse") + + +@_attrs_define +class GetFileInfoResponse: + """ + Attributes: + file_id (str): Unique file identifier + graph_id (str): Graph database identifier + table_id (str): Table identifier + file_name (str): Original file name + file_format (str): File format (parquet, csv, etc.) + size_bytes (int): File size in bytes + upload_status (str): Current upload status + upload_method (str): Upload method used + s3_key (str): S3 object key + table_name (Union[None, Unset, str]): Table name + row_count (Union[None, Unset, int]): Estimated row count + created_at (Union[None, Unset, str]): File creation timestamp + uploaded_at (Union[None, Unset, str]): File upload completion timestamp + """ + + file_id: str + graph_id: str + table_id: str + file_name: str + file_format: str + size_bytes: int + upload_status: str + upload_method: str + s3_key: str + table_name: Union[None, Unset, str] = UNSET + row_count: Union[None, Unset, int] = UNSET + created_at: Union[None, Unset, str] = UNSET + uploaded_at: Union[None, Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + file_id = self.file_id + + graph_id = self.graph_id + + table_id = self.table_id + + file_name = self.file_name + + file_format = self.file_format + + size_bytes = self.size_bytes + + upload_status = self.upload_status + + upload_method = self.upload_method + + s3_key = self.s3_key + + table_name: Union[None, Unset, str] + if isinstance(self.table_name, Unset): + table_name = UNSET + else: + table_name = self.table_name + + row_count: Union[None, Unset, int] + if isinstance(self.row_count, Unset): + row_count = UNSET + else: + row_count = self.row_count + + created_at: Union[None, Unset, str] + if isinstance(self.created_at, Unset): + created_at = UNSET + else: + created_at = self.created_at + + uploaded_at: Union[None, Unset, str] + if isinstance(self.uploaded_at, Unset): + uploaded_at = UNSET + else: + uploaded_at = self.uploaded_at + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "file_id": file_id, + "graph_id": graph_id, + "table_id": table_id, + "file_name": file_name, + "file_format": file_format, + "size_bytes": size_bytes, + "upload_status": upload_status, + "upload_method": upload_method, + "s3_key": s3_key, + } + ) + if table_name is not UNSET: + field_dict["table_name"] = table_name + if row_count is not UNSET: + field_dict["row_count"] = row_count + if created_at is not UNSET: + field_dict["created_at"] = created_at + if uploaded_at is not UNSET: + field_dict["uploaded_at"] = uploaded_at + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + file_id = d.pop("file_id") + + graph_id = d.pop("graph_id") + + table_id = d.pop("table_id") + + file_name = d.pop("file_name") + + file_format = d.pop("file_format") + + size_bytes = d.pop("size_bytes") + + upload_status = d.pop("upload_status") + + upload_method = d.pop("upload_method") + + s3_key = d.pop("s3_key") + + def _parse_table_name(data: object) -> Union[None, Unset, str]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, str], data) + + table_name = _parse_table_name(d.pop("table_name", UNSET)) + + def _parse_row_count(data: object) -> Union[None, Unset, int]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, int], data) + + row_count = _parse_row_count(d.pop("row_count", UNSET)) + + def _parse_created_at(data: object) -> Union[None, Unset, str]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, str], data) + + created_at = _parse_created_at(d.pop("created_at", UNSET)) + + def _parse_uploaded_at(data: object) -> Union[None, Unset, str]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, str], data) + + uploaded_at = _parse_uploaded_at(d.pop("uploaded_at", UNSET)) + + get_file_info_response = cls( + file_id=file_id, + graph_id=graph_id, + table_id=table_id, + file_name=file_name, + file_format=file_format, + size_bytes=size_bytes, + upload_status=upload_status, + upload_method=upload_method, + s3_key=s3_key, + table_name=table_name, + row_count=row_count, + created_at=created_at, + uploaded_at=uploaded_at, + ) + + get_file_info_response.additional_properties = d + return get_file_info_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/list_table_files_response.py b/robosystems_client/models/list_table_files_response.py new file mode 100644 index 0000000..b53e776 --- /dev/null +++ b/robosystems_client/models/list_table_files_response.py @@ -0,0 +1,105 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.file_info import FileInfo + + +T = TypeVar("T", bound="ListTableFilesResponse") + + +@_attrs_define +class ListTableFilesResponse: + """ + Attributes: + graph_id (str): Graph database identifier + table_name (str): Table name + files (list['FileInfo']): List of files in the table + total_files (int): Total number of files + total_size_bytes (int): Total size of all files in bytes + """ + + graph_id: str + table_name: str + files: list["FileInfo"] + total_files: int + total_size_bytes: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + graph_id = self.graph_id + + table_name = self.table_name + + files = [] + for files_item_data in self.files: + files_item = files_item_data.to_dict() + files.append(files_item) + + total_files = self.total_files + + total_size_bytes = self.total_size_bytes + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "graph_id": graph_id, + "table_name": table_name, + "files": files, + "total_files": total_files, + "total_size_bytes": total_size_bytes, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.file_info import FileInfo + + d = dict(src_dict) + graph_id = d.pop("graph_id") + + table_name = d.pop("table_name") + + files = [] + _files = d.pop("files") + for files_item_data in _files: + files_item = FileInfo.from_dict(files_item_data) + + files.append(files_item) + + total_files = d.pop("total_files") + + total_size_bytes = d.pop("total_size_bytes") + + list_table_files_response = cls( + graph_id=graph_id, + table_name=table_name, + files=files, + total_files=total_files, + total_size_bytes=total_size_bytes, + ) + + list_table_files_response.additional_properties = d + return list_table_files_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/list_table_files_v1_graphs_graph_id_tables_table_name_files_get_response_list_table_files_v1_graphs_graph_id_tables_table_name_files_get.py b/robosystems_client/models/list_table_files_v1_graphs_graph_id_tables_table_name_files_get_response_list_table_files_v1_graphs_graph_id_tables_table_name_files_get.py deleted file mode 100644 index a48ee38..0000000 --- a/robosystems_client/models/list_table_files_v1_graphs_graph_id_tables_table_name_files_get_response_list_table_files_v1_graphs_graph_id_tables_table_name_files_get.py +++ /dev/null @@ -1,47 +0,0 @@ -from collections.abc import Mapping -from typing import Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -T = TypeVar( - "T", - bound="ListTableFilesV1GraphsGraphIdTablesTableNameFilesGetResponseListTableFilesV1GraphsGraphIdTablesTableNameFilesGet", -) - - -@_attrs_define -class ListTableFilesV1GraphsGraphIdTablesTableNameFilesGetResponseListTableFilesV1GraphsGraphIdTablesTableNameFilesGet: - """ """ - - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - list_table_files_v1_graphs_graph_id_tables_table_name_files_get_response_list_table_files_v1_graphs_graph_id_tables_table_name_files_get = cls() - - list_table_files_v1_graphs_graph_id_tables_table_name_files_get_response_list_table_files_v1_graphs_graph_id_tables_table_name_files_get.additional_properties = d - return list_table_files_v1_graphs_graph_id_tables_table_name_files_get_response_list_table_files_v1_graphs_graph_id_tables_table_name_files_get - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/robosystems_client/models/get_file_info_v1_graphs_graph_id_tables_files_file_id_get_response_get_file_info_v1_graphs_graph_id_tables_files_file_id_get.py b/robosystems_client/models/update_file_status_response_updatefilestatus.py similarity index 59% rename from robosystems_client/models/get_file_info_v1_graphs_graph_id_tables_files_file_id_get_response_get_file_info_v1_graphs_graph_id_tables_files_file_id_get.py rename to robosystems_client/models/update_file_status_response_updatefilestatus.py index 7d167bc..57e3960 100644 --- a/robosystems_client/models/get_file_info_v1_graphs_graph_id_tables_files_file_id_get_response_get_file_info_v1_graphs_graph_id_tables_files_file_id_get.py +++ b/robosystems_client/models/update_file_status_response_updatefilestatus.py @@ -4,14 +4,11 @@ from attrs import define as _attrs_define from attrs import field as _attrs_field -T = TypeVar( - "T", - bound="GetFileInfoV1GraphsGraphIdTablesFilesFileIdGetResponseGetFileInfoV1GraphsGraphIdTablesFilesFileIdGet", -) +T = TypeVar("T", bound="UpdateFileStatusResponseUpdatefilestatus") @_attrs_define -class GetFileInfoV1GraphsGraphIdTablesFilesFileIdGetResponseGetFileInfoV1GraphsGraphIdTablesFilesFileIdGet: +class UpdateFileStatusResponseUpdatefilestatus: """ """ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) @@ -25,10 +22,10 @@ def to_dict(self) -> dict[str, Any]: @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: d = dict(src_dict) - get_file_info_v1_graphs_graph_id_tables_files_file_id_get_response_get_file_info_v1_graphs_graph_id_tables_files_file_id_get = cls() + update_file_status_response_updatefilestatus = cls() - get_file_info_v1_graphs_graph_id_tables_files_file_id_get_response_get_file_info_v1_graphs_graph_id_tables_files_file_id_get.additional_properties = d - return get_file_info_v1_graphs_graph_id_tables_files_file_id_get_response_get_file_info_v1_graphs_graph_id_tables_files_file_id_get + update_file_status_response_updatefilestatus.additional_properties = d + return update_file_status_response_updatefilestatus @property def additional_keys(self) -> list[str]: diff --git a/robosystems_client/models/update_file_v1_graphs_graph_id_tables_files_file_id_patch_response_update_file_v1_graphs_graph_id_tables_files_file_id_patch.py b/robosystems_client/models/update_file_v1_graphs_graph_id_tables_files_file_id_patch_response_update_file_v1_graphs_graph_id_tables_files_file_id_patch.py deleted file mode 100644 index f796fff..0000000 --- a/robosystems_client/models/update_file_v1_graphs_graph_id_tables_files_file_id_patch_response_update_file_v1_graphs_graph_id_tables_files_file_id_patch.py +++ /dev/null @@ -1,47 +0,0 @@ -from collections.abc import Mapping -from typing import Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -T = TypeVar( - "T", - bound="UpdateFileV1GraphsGraphIdTablesFilesFileIdPatchResponseUpdateFileV1GraphsGraphIdTablesFilesFileIdPatch", -) - - -@_attrs_define -class UpdateFileV1GraphsGraphIdTablesFilesFileIdPatchResponseUpdateFileV1GraphsGraphIdTablesFilesFileIdPatch: - """ """ - - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - update_file_v1_graphs_graph_id_tables_files_file_id_patch_response_update_file_v1_graphs_graph_id_tables_files_file_id_patch = cls() - - update_file_v1_graphs_graph_id_tables_files_file_id_patch_response_update_file_v1_graphs_graph_id_tables_files_file_id_patch.additional_properties = d - return update_file_v1_graphs_graph_id_tables_files_file_id_patch_response_update_file_v1_graphs_graph_id_tables_files_file_id_patch - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties