Metadata-Version: 2.4
Name: hydrousdb
Version: 1.0.0
Summary: Official Python SDK for HydrousDB — records, auth, and analytics.
Project-URL: Homepage, https://hydrousdb.com
Project-URL: Repository, https://github.com/hydrousdb/hydrousdb-python
Project-URL: Bug Tracker, https://github.com/hydrousdb/hydrousdb-python/issues
License: MIT License
        
        Copyright (c) 2025 HydrousDB
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: analytics,auth,database,hydrousdb,sdk
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Database
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.8
Requires-Dist: typing-extensions>=4.0; python_version < '3.11'
Provides-Extra: dev
Requires-Dist: mypy>=1.0; extra == 'dev'
Requires-Dist: pytest-mock>=3.0; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: responses>=0.23; extra == 'dev'
Requires-Dist: ruff>=0.1; extra == 'dev'
Description-Content-Type: text/markdown

# hydrousdb · Python SDK

Official Python client for **HydrousDB** — records, auth, and analytics in one package.

[![PyPI version](https://img.shields.io/pypi/v/hydrousdb)](https://pypi.org/project/hydrousdb/)
[![Python versions](https://img.shields.io/pypi/pyversions/hydrousdb)](https://pypi.org/project/hydrousdb/)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)

---

## Installation

```bash
pip install hydrousdb
```

Requires **Python 3.8+**. Zero mandatory third-party dependencies — uses only the standard library.

---

## Quick start

```python
from hydrousdb import create_client

db = create_client(
    auth_key="your-auth-key",      # auth service key
    bucket_key="your-bucket-key",  # records, analytics & buckets key
)
```

> **Environment variable pattern (recommended)**
> ```python
> import os
> from hydrousdb import create_client
>
> db = create_client(
>     auth_key=os.environ["HYDROUS_AUTH_KEY"],
>     bucket_key=os.environ["HYDROUS_BUCKET_KEY"],
> )
> ```

---

## Records

### Get a record

```python
result = db.records.get("rec_abc123")
print(result["data"]["name"])

# With version history
result = db.records.get("rec_abc123", show_history=True)
print(result["history"])
```

### Query a collection

```python
# Simple query
result = db.records.query(limit=50, sort_order="desc")

# Filtered query
result = db.records.query(
    filters=[{"field": "status", "op": "==", "value": "active"}],
    time_scope="7d",
)
for record in result["data"]:
    print(record)

# Paginate manually
cursor = None
while True:
    result = db.records.query(limit=100, cursor=cursor)
    process(result["data"])
    cursor = result["meta"].get("nextCursor")
    if not cursor:
        break

# Or fetch everything automatically
all_records = db.records.query_all(
    filters=[{"field": "type", "op": "==", "value": "invoice"}]
)
```

**Supported filter operators:** `== != > < >= <= contains`
**Maximum 3 filters per query.**

### Insert a record

```python
result = db.records.insert(
    values={"name": "Alice", "score": 99},
    queryable_fields=["name"],
)
print(result["meta"]["id"])  # rec_...
```

### Update a record

```python
db.records.update(
    "rec_abc123",
    values={"score": 100},
    track_history=True,
)
```

### Delete a record

```python
db.records.delete("rec_abc123")
```

### Check existence (HEAD)

```python
info = db.records.exists("rec_abc123")
if info:
    print("Found, updated at", info["updated_at"])
else:
    print("Not found")
```

### Batch operations

```python
# Batch insert (up to 500)
result = db.records.batch_insert(
    [{"name": "Alice"}, {"name": "Bob"}],
    queryable_fields=["name"],
)
print(result["meta"]["successful"])

# Batch update
db.records.batch_update([
    {"recordId": "rec_1", "values": {"status": "archived"}},
    {"recordId": "rec_2", "values": {"status": "archived"}},
])

# Batch delete
db.records.batch_delete(["rec_1", "rec_2", "rec_3"])
```

---

## Auth

### Sign up / Sign in

```python
# Sign up
result = db.auth.sign_up(
    "alice@example.com",
    "Str0ngP@ss!",
    full_name="Alice Smith",
)
session_id    = result["session"]["sessionId"]
refresh_token = result["session"]["refreshToken"]

# Sign in
result = db.auth.sign_in("alice@example.com", "Str0ngP@ss!")
session_id = result["session"]["sessionId"]
```

### Session management

```python
# Validate session (use on every protected request)
try:
    result = db.auth.validate_session(session_id)
    user = result["data"]
except HydrousError as e:
    if e.status == 401:
        # Session expired
        pass

# Refresh session
result = db.auth.refresh_session(refresh_token)
new_session = result["session"]

# Sign out (single device)
db.auth.sign_out(session_id=session_id)

# Sign out (all devices)
db.auth.sign_out(all_devices=True, user_id="user_abc")
```

### User management

```python
# Get user
result = db.auth.get_user("user_abc123")
print(result["data"]["email"])

# List users (paginated)
result = db.auth.list_users(limit=50)
users  = result["data"]
cursor = result["meta"].get("nextCursor")

# Fetch all users automatically
all_users = db.auth.list_all_users()

# Update user
db.auth.update_user("user_abc", {"fullName": "Bob Smith"})

# Delete user
db.auth.delete_user("user_abc123")
```

### Password management

```python
# Change password
db.auth.change_password("user_abc", "Old@Pass1", "New@Pass2")

# Request reset email
db.auth.request_password_reset("alice@example.com")

# Confirm reset
db.auth.confirm_password_reset("tok_...", "New@Pass2")
```

### Account control

```python
# Lock for 30 minutes
db.auth.lock_account("user_abc", duration_ms=30 * 60 * 1000)

# Unlock
db.auth.unlock_account("user_abc")
```

---

## Analytics

### Count

```python
result = db.analytics.count()
print(result["data"]["count"])  # 1234

# Scoped to date range
result = db.analytics.count(
    date_range={"startDate": "2025-01-01", "endDate": "2025-12-31"}
)
```

### Distribution (histogram)

```python
result = db.analytics.distribution("status")
for item in result["data"]:
    print(item["value"], item["count"])
```

### Sum

```python
result = db.analytics.sum("revenue", group_by="region")
print(result["data"]["total"])
```

### Time series

```python
result = db.analytics.time_series(granularity="day")
for point in result["data"]:
    print(point["date"], point["count"])
```

### Field time series

```python
result = db.analytics.field_time_series(
    "revenue",
    aggregation="sum",
    granularity="month",
)
```

### Top N

```python
result = db.analytics.top_n("country", 5)
for item in result["data"]:
    print(item["label"], item["count"])
```

### Stats (min/max/avg/stddev/percentiles)

```python
result = db.analytics.stats("score")
data = result["data"]
print(data["avg"], data["p99"])
```

### Multi-metric (dashboard stat cards)

```python
result = db.analytics.multi_metric([
    {"name": "totalRevenue", "field": "amount",  "aggregation": "sum"},
    {"name": "avgScore",     "field": "score",   "aggregation": "avg"},
    {"name": "userCount",    "field": "userId",  "aggregation": "count"},
])
data = result["data"]
print(data["totalRevenue"], data["avgScore"])
```

### Storage stats

```python
result = db.analytics.storage_stats()
print(result["data"]["totalRecords"], result["data"]["totalBytes"])
```

### Cross-bucket comparison

```python
result = db.analytics.cross_bucket(
    bucket_keys=["sales", "refunds", "trials"],
    field="amount",
    aggregation="sum",
)
```

---

## Error handling

```python
from hydrousdb import HydrousError, HydrousNetworkError, HydrousTimeoutError

try:
    result = db.records.get("rec_missing")
except HydrousError as e:
    print(e.status)      # 404
    print(e.code)        # "RECORD_NOT_FOUND"
    print(e.message)     # Human-readable message
    print(e.details)     # List of validation details
    print(e.request_id)  # Server request ID for support
except HydrousTimeoutError as e:
    print(f"Timed out after {e.timeout_ms}ms")
except HydrousNetworkError as e:
    print(f"Network failure: {e.message}")
```

---

## Configuration

| Parameter   | Type    | Default                                              | Description                              |
|-------------|---------|------------------------------------------------------|------------------------------------------|
| `auth_key`  | `str`   | **required**                                         | Auth service key                         |
| `bucket_key`| `str`   | **required**                                         | Bucket key (records, analytics, buckets) |
| `base_url`  | `str`   | `https://db-api-82687684612.us-central1.run.app`     | Override the API base URL                |
| `timeout`   | `float` | `30.0`                                               | Request timeout in **seconds**           |
| `retries`   | `int`   | `2`                                                  | Auto-retries on transient errors         |

---

## Type hints

All response values are plain Python dicts at runtime. The `hydrousdb.types` module
exports `TypedDict` definitions for IDE autocompletion and static analysis:

```python
from hydrousdb.types import GetRecordResponse, SignInResponse, AnalyticsResult
```

---

## License

MIT © HydrousDB
