Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .openapi-generator/FILES
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ docs/ExecuteSavedQueryRequest.md
docs/FinalizeUploadPart.md
docs/FinalizeUploadRequest.md
docs/FinalizeUploadResponse.md
docs/ForkDatabaseRequest.md
docs/GetConnectionResponse.md
docs/GetDatabaseContextResponse.md
docs/GetResultResponse.md
Expand Down Expand Up @@ -214,6 +215,7 @@ hotdata/models/execute_saved_query_request.py
hotdata/models/finalize_upload_part.py
hotdata/models/finalize_upload_request.py
hotdata/models/finalize_upload_response.py
hotdata/models/fork_database_request.py
hotdata/models/get_connection_response.py
hotdata/models/get_database_context_response.py
hotdata/models/get_result_response.py
Expand Down Expand Up @@ -343,6 +345,7 @@ test/test_execute_saved_query_request.py
test/test_finalize_upload_part.py
test/test_finalize_upload_request.py
test/test_finalize_upload_response.py
test/test_fork_database_request.py
test/test_get_connection_response.py
test/test_get_database_context_response.py
test/test_get_result_response.py
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- feat(databases): add fork endpoint

## [0.7.0] - 2026-07-14

### Changed
Expand Down
3 changes: 2 additions & 1 deletion docs/CreateDatabaseRequest.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ Request body for POST /databases

Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**default_catalog** | **str** | Optional name the database's auto-created default catalog answers to inside its query scope. Must be a valid SQL identifier (`[a-z0-9_]`, not starting with a digit) and may not collide with the reserved catalog names `hotdata`, `datasets`, or `information_schema`. Defaults to `default` when omitted, so `default.main.<table>` keeps working. | [optional]
**default_catalog** | **str** | Optional name the database's auto-created default catalog answers to inside its query scope. Must be a valid SQL identifier (`[a-z0-9_]`, not starting with a digit) and may not collide with the reserved catalog names `hotdata` or `information_schema`. Defaults to `default` when omitted, so `default.main.<table>` keeps working. | [optional]
**default_schema** | **str** | Optional schema that unqualified table names resolve to inside this database's query scope. Must be a valid SQL identifier (`[a-z0-9_]`, not starting with a digit). When omitted, a database that declares exactly one schema adopts that schema as its default; otherwise unqualified names resolve to `main`. Fully-qualified names (`<catalog>.<schema>.<table>`) are unaffected, and a per-query `default_schema` still takes precedence. | [optional]
**expires_at** | **str** | When this database expires. Accepts either an RFC 3339 timestamp (e.g. `\"2026-06-01T00:00:00Z\"`) or a relative duration suffixed with `h` (hours), `m` (minutes), or `d` (days) — for example `\"24h\"`, `\"48h\"`, or `\"7d\"`. Omitted (or empty) means the database never expires. Expiry is best-effort: the database will not be deleted before `expires_at`, but cleanup may run later than the exact timestamp. | [optional]
**name** | **str** | Optional free-form display label (for UIs/CLIs). Not unique. Not an identifier — databases are always addressed by `id`. Accepts the legacy `description` key as an alias so clients that predate the rename keep populating this field. | [optional]
**schemas** | [**List[DatabaseDefaultSchemaDecl]**](DatabaseDefaultSchemaDecl.md) | Optional schemas/tables to declare on the database's auto-created default catalog. Tables declared here can be loaded via the standard managed-table load endpoint targeting `default_connection_id`. Omitted or empty means the default catalog starts empty. | [optional]
Expand Down
1 change: 1 addition & 0 deletions docs/CreateDatabaseResponse.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**default_catalog** | **str** | Name the database's default catalog answers to inside its query scope (`default` unless overridden at create time). |
**default_connection_id** | **str** | Internal id of the connection that backs this database's `default` catalog. Workspace-level connection endpoints (list, get, health, delete, cache purge) refuse to act on this id — it is exposed only for the managed-tables load endpoint (`POST /v1/connections/{id}/schemas/{s}/tables/{t}/loads`) so callers can publish parquet into tables declared at database-create time. Addressing it directly in SQL is not the recommended path — use `default` inside an `X-Database-Id` scope instead. |
**default_schema** | **str** | Schema that unqualified table names resolve to inside this database's query scope. `main` unless the database declares a single schema or a `default_schema` was set at create time. |
**expires_at** | **datetime** | When this database expires. | [optional]
**id** | **str** | |
**name** | **str** | | [optional]
Expand Down
1 change: 1 addition & 0 deletions docs/DatabaseDetailResponse.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Name | Type | Description | Notes
**created_at** | **datetime** | When the database was created. | [optional]
**default_catalog** | **str** | Name the database's default catalog answers to inside its query scope (`default` unless overridden at create time). |
**default_connection_id** | **str** | |
**default_schema** | **str** | Schema that unqualified table names resolve to inside this database's query scope. `main` unless the database declares a single schema or a `default_schema` was set at create time. |
**expires_at** | **datetime** | When this database expires. | [optional]
**id** | **str** | |
**name** | **str** | | [optional]
Expand Down
1 change: 1 addition & 0 deletions docs/DatabaseSummary.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**created_at** | **datetime** | When the database was created. | [optional]
**default_catalog** | **str** | Name the database's default catalog answers to inside its query scope. |
**default_schema** | **str** | Schema that unqualified table names resolve to inside this database's query scope. `main` unless the database declares a single schema or a `default_schema` was set at create time. |
**expires_at** | **datetime** | | [optional]
**id** | **str** | |
**name** | **str** | | [optional]
Expand Down
93 changes: 92 additions & 1 deletion docs/DatabasesApi.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Method | HTTP request | Description
[**create_database**](DatabasesApi.md#create_database) | **POST** /v1/databases | Create database
[**delete_database**](DatabasesApi.md#delete_database) | **DELETE** /v1/databases/{database_id} | Delete database
[**detach_database_catalog**](DatabasesApi.md#detach_database_catalog) | **DELETE** /v1/databases/{database_id}/catalogs/{connection_id} | Detach catalog from database
[**fork_database**](DatabasesApi.md#fork_database) | **POST** /v1/databases/{database_id}/fork | Fork database
[**get_database**](DatabasesApi.md#get_database) | **GET** /v1/databases/{database_id} | Get database
[**list_databases**](DatabasesApi.md#list_databases) | **GET** /v1/databases | List databases
[**load_database_table**](DatabasesApi.md#load_database_table) | **POST** /v1/databases/{database_id}/schemas/{schema}/tables/{table}/loads | Load database table from upload or query result
Expand Down Expand Up @@ -292,7 +293,7 @@ void (empty response body)

Create database

Create a new database (a metadata-only grouping). A managed default catalog is auto-created and addressable inside the database as `default` (or the optional `default_catalog` name), with a `main` schema pre-declared so `default.main.<table>` works out of the box. The optional `name` is a free-form display label and is not required to be unique. Optional `default_catalog` overrides the name the default catalog answers to; it must be a valid SQL identifier and may not collide with the reserved catalog names `hotdata`, `datasets`, or `information_schema`. Optional `schemas` declares additional schemas/tables on the default catalog at create time; declared tables can be loaded via the standard managed-tables-load endpoint targeting `default_connection_id`. Optional `expires_at` sets when the database expires — accepts either an RFC 3339 timestamp or a relative duration suffixed with `h` (hours), `m` (minutes), or `d` (days), e.g. `24h`, `48h`, `90m`, `7d`. When omitted, the database never expires. Expiry is best-effort: the database will not be deleted before `expires_at`, but cleanup may run later than the exact timestamp.
Create a new database (a metadata-only grouping). A managed default catalog is auto-created and addressable inside the database as `default` (or the optional `default_catalog` name), with a `main` schema pre-declared so `default.main.<table>` works out of the box. The optional `name` is a free-form display label and is not required to be unique. Optional `default_catalog` overrides the name the default catalog answers to; it must be a valid SQL identifier and may not collide with the reserved catalog names `hotdata` or `information_schema`. Optional `schemas` declares additional schemas/tables on the default catalog at create time; declared tables can be loaded via the standard managed-tables-load endpoint targeting `default_connection_id`. Optional `expires_at` sets when the database expires — accepts either an RFC 3339 timestamp or a relative duration suffixed with `h` (hours), `m` (minutes), or `d` (days), e.g. `24h`, `48h`, `90m`, `7d`. When omitted, the database never expires. Expiry is best-effort: the database will not be deleted before `expires_at`, but cleanup may run later than the exact timestamp.

### Example

Expand Down Expand Up @@ -542,6 +543,96 @@ void (empty response body)

[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)

# **fork_database**
> CreateDatabaseResponse fork_database(database_id, fork_database_request)

Fork database

Create a new database that is an independent fork of an existing one. The fork has its own default catalog and contains the same schemas, tables, and data as the source; the source is left unchanged. External catalogs attached to the source are re-attached to the fork. Optional `name` sets the fork's display label (defaults to the source's). Optional `expires_at` sets when the fork expires — accepts an RFC 3339 timestamp or a relative duration suffixed with `h` (hours), `m` (minutes), or `d` (days), e.g. `24h`, `90m`, `7d`. When omitted, a still-future expiry on the source is carried over; otherwise the fork never expires. Any indexes on the source's tables are not carried over.

### Example

* Api Key Authentication (WorkspaceId):
* Bearer Authentication (BearerAuth):

```python
import hotdata
from hotdata.models.create_database_response import CreateDatabaseResponse
from hotdata.models.fork_database_request import ForkDatabaseRequest
from hotdata.rest import ApiException
from pprint import pprint

# Defining the host is optional and defaults to https://api.hotdata.dev
# See configuration.py for a list of all supported configuration parameters.
configuration = hotdata.Configuration(
host = "https://api.hotdata.dev"
)

# The client must configure the authentication and authorization parameters
# in accordance with the API server security policy.
# Examples for each auth method are provided below, use the example that
# satisfies your auth use case.

# Configure API key authorization: WorkspaceId
configuration.api_key['WorkspaceId'] = os.environ["API_KEY"]

# Uncomment below to setup prefix (e.g. Bearer) for API key, if needed
# configuration.api_key_prefix['WorkspaceId'] = 'Bearer'

# Configure Bearer authorization: BearerAuth
configuration = hotdata.Configuration(
access_token = os.environ["BEARER_TOKEN"]
)

# Enter a context with an instance of the API client
with hotdata.ApiClient(configuration) as api_client:
# Create an instance of the API class
api_instance = hotdata.DatabasesApi(api_client)
database_id = 'database_id_example' # str | Source database ID
fork_database_request = hotdata.ForkDatabaseRequest() # ForkDatabaseRequest |

try:
# Fork database
api_response = api_instance.fork_database(database_id, fork_database_request)
print("The response of DatabasesApi->fork_database:\n")
pprint(api_response)
except Exception as e:
print("Exception when calling DatabasesApi->fork_database: %s\n" % e)
```



### Parameters


Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**database_id** | **str**| Source database ID |
**fork_database_request** | [**ForkDatabaseRequest**](ForkDatabaseRequest.md)| |

### Return type

[**CreateDatabaseResponse**](CreateDatabaseResponse.md)

### Authorization

[WorkspaceId](../README.md#WorkspaceId), [BearerAuth](../README.md#BearerAuth)

### HTTP request headers

- **Content-Type**: application/json
- **Accept**: application/json

### HTTP response details

| Status code | Description | Response headers |
|-------------|-------------|------------------|
**201** | Database forked | - |
**400** | The source database can&#39;t be forked as-is (for example, it uses a storage backend that does not support forking, or one of its tables has rows that were individually deleted or updated) | - |
**404** | Source database not found | - |

[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)

# **get_database**
> DatabaseDetailResponse get_database(database_id)

Expand Down
31 changes: 31 additions & 0 deletions docs/ForkDatabaseRequest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# ForkDatabaseRequest

Request body for POST /databases/{database_id}/fork

## Properties

Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**expires_at** | **str** | When the fork expires. Accepts either an RFC 3339 timestamp (e.g. &#x60;\&quot;2026-06-01T00:00:00Z\&quot;&#x60;) or a relative duration suffixed with &#x60;h&#x60; (hours), &#x60;m&#x60; (minutes), or &#x60;d&#x60; (days) — for example &#x60;\&quot;24h\&quot;&#x60; or &#x60;\&quot;7d\&quot;&#x60;. When omitted, a still-future expiry on the source is carried over; otherwise the fork never expires. | [optional]
**name** | **str** | Optional display label for the fork. When omitted, the source database&#39;s name (if any) is carried over. | [optional]

## Example

```python
from hotdata.models.fork_database_request import ForkDatabaseRequest

# TODO update the JSON string below
json = "{}"
# create an instance of ForkDatabaseRequest from a JSON string
fork_database_request_instance = ForkDatabaseRequest.from_json(json)
# print the JSON string representation of the object
print(ForkDatabaseRequest.to_json())

# convert the object into a dict
fork_database_request_dict = fork_database_request_instance.to_dict()
# create an instance of ForkDatabaseRequest from a dict
fork_database_request_from_dict = ForkDatabaseRequest.from_dict(fork_database_request_dict)
```
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)


2 changes: 1 addition & 1 deletion docs/WorkspaceUsageResponse.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Name | Type | Description | Notes
**bytes_scanned** | **int** | Sum of &#x60;bytes_scanned&#x60; across all completed/failed query runs since &#x60;since&#x60;. Null bytes (queries that touched no row data) contribute 0. |
**query_count** | **int** | Number of query runs (succeeded + failed) since &#x60;since&#x60;. |
**since** | **datetime** | The period start used for this response (echoed back for the caller to verify). |
**storage_bytes** | **int** | The workspace&#39;s current stored-data footprint in bytes, measured at request time: managed-database and dataset data, plus un-consumed uploads, connection caches, and search-index artifacts. |
**storage_bytes** | **int** | The workspace&#39;s current stored-data footprint in bytes, measured at request time: managed-database data, plus un-consumed uploads, connection caches, and search-index artifacts. |
**storage_captured_at** | **datetime** | When &#x60;storage_bytes&#x60; was measured (the time this response was produced). | [optional]

## Example
Expand Down
2 changes: 2 additions & 0 deletions hotdata/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
"FinalizeUploadPart",
"FinalizeUploadRequest",
"FinalizeUploadResponse",
"ForkDatabaseRequest",
"GetConnectionResponse",
"GetDatabaseContextResponse",
"GetResultResponse",
Expand Down Expand Up @@ -255,6 +256,7 @@
from hotdata.models.finalize_upload_part import FinalizeUploadPart as FinalizeUploadPart
from hotdata.models.finalize_upload_request import FinalizeUploadRequest as FinalizeUploadRequest
from hotdata.models.finalize_upload_response import FinalizeUploadResponse as FinalizeUploadResponse
from hotdata.models.fork_database_request import ForkDatabaseRequest as ForkDatabaseRequest
from hotdata.models.get_connection_response import GetConnectionResponse as GetConnectionResponse
from hotdata.models.get_database_context_response import GetDatabaseContextResponse as GetDatabaseContextResponse
from hotdata.models.get_result_response import GetResultResponse as GetResultResponse
Expand Down
Loading