Metadata-Version: 2.4
Name: liorandb-driver
Version: 1.0.1
Summary: Python HTTP driver for LioranDB (API-compatible with @liorandb/driver).
Author: LioranDB
License: MIT License
        
        Copyright (c) 2026 Lioran Group Official
        
        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.
        
Project-URL: Homepage, https://github.com/liorandb/ldb-driver-python
Keywords: liorandb,database,driver,http
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
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: Typing :: Typed
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx>=0.27.0
Dynamic: license-file

# ldb-driver-python

Python async HTTP driver for LioranDB.

This repo implements a Python package that mirrors the *API shape* of the Node.js driver shown in `log.txt` (the `@liorandb/driver` TypeScript driver). The Python version is designed so you can write code that looks almost identical to the TS examples.

## Status / parity

- Implemented: `LioranClient`, `LioranManager`, `DB`, `Collection`, HTTP auth (JWT + connection-string header), URI parsing (`http(s)://`, `lioran://`, `liorandb(s)://`), and the main database/collection endpoints from the log.
- Not a 1:1 clone: the TypeScript `types.ts` response/DTO typing is **not** fully replicated (Python returns `dict`/`list`), and the library is **async-first** (uses `httpx.AsyncClient`).

If you want strict, fully-typed Python models matching `types.ts`, tell me and I'll generate `pydantic` models for every response type in the log.

## Install

```bash
pip install liorandb-driver
```

## Quick start

```py
import asyncio
from liorandb_driver import LioranClient

async def main():
    client = LioranClient("lioran://username:password@localhost:4000")
    await client.connect()

    db = client.db("mydb")
    users = db.collection("users")

    await users.insertOne({"name": "Ada"})
    print(await users.find({}))

    await client.aclose()

asyncio.run(main())
```

## URI formats (same idea as TS)

### 1) Host URL (no auth)

Use this if you want to call `login()` manually (or set a token later).

- `http://host:port`
- `https://host:port`

Example:

```py
client = LioranClient("http://localhost:4000")
auth = await client.login("admin", "password")
```

### 2) Legacy auth URI (`lioran://`)

Same behavior as the TS `parseLegacyLioranUri`:

- `lioran://host:port` (no creds in URI; you must `login()`/`setToken()` later)
- `liorans://host:port` (HTTPS)
- `lioran://username:password@host:port` (creds in URI; `connect()` logs in)
- `liorans://username:password@host:port` (HTTPS)

Example:

```py
client = LioranClient("lioran://admin:password@localhost:4000")
await client.connect()
```

### 3) Connection string (`liorandb://` / `liorandbs://`)

Same idea as TS `liorandb://` parsing: it stores the full connection string and sends it as a header for auth.

- `liorandb://username:password@host:port/<database>` (defaults port to `4000` if not provided)
- `liorandbs://...` uses HTTPS when building the base URL

Example:

```py
client = LioranClient("liorandb://user:pass@localhost:4000/mydb")
await client.connect()  # sets connection-string auth mode
db = client.db("mydb")
```

## API reference (Python + TS-style aliases)

This library provides **snake_case** methods *and* **TypeScript-style camelCase aliases** so you can keep the same syntax as the Node driver.

### Client (`LioranClient`)

Auth/session:
- `await client.connect()`
- `await client.login(username, password)`
- `await client.super_admin_login(secret)` / `await client.superAdminLogin(secret)`
- `client.set_token(token)` / `client.setToken(token)`
- `client.set_connection_string(cs)` / `client.setConnectionString(cs)`
- `client.logout()`
- `client.is_authenticated()` / `client.isAuthenticated()`
- `await client.aclose()` (closes the underlying HTTP client)

User/admin endpoints:
- `await client.me()`
- `await client.register(user_id, username=None, password=None, role="user", external_user_id=None)`
- `await client.list_users()` / `await client.listUsers()`
- `await client.issue_user_token(user_id)` / `await client.issueUserToken(user_id)`
- `await client.update_my_cors(origins)` / `await client.updateMyCors(origins)`
- `await client.update_user_cors(user_id, origins)` / `await client.updateUserCors(user_id, origins)`

Info/health/docs:
- `await client.health()`
- `await client.info()`
- `await client.list_docs()` / `await client.listDocs()`
- `await client.get_doc(id)` / `await client.getDoc(id)`

Databases:
- `db = client.db(name)`
- `await client.list_databases()` / `await client.listDatabases()`
- `await client.count_databases(user_id=None)` / `await client.countDatabases(user_id=None)`
- `await client.list_user_databases(user_id)` / `await client.listUserDatabases(user_id)`
- `await client.create_database(name, owner_user_id=None)` / `await client.createDatabase(name, ownerUserId=None)`
- `await client.drop_database(name)` / `await client.dropDatabase(name)`
- `await client.database_stats(name)` / `await client.databaseStats(name)`

Maintenance:
- `await client.maintenance_status()` / `await client.maintenanceStatus()`
- `await client.list_snapshots()` / `await client.listSnapshots()`
- `await client.create_snapshot_now()` / `await client.createSnapshotNow()`
- `await client.compact_all_databases()` / `await client.compactAllDatabases()`
- `await client.stop_server(secret)` / `await client.stopServer(secret)`
- `await client.pause_server(secret)` / `await client.pauseServer(secret)`
- `await client.resume_server(secret)` / `await client.resumeServer(secret)`
- `await client.restore_server_snapshot(secret, snapshotPath)` / `await client.restoreServerSnapshot(secret, snapshotPath)`

Core:
- `await client.core_status()` / `await client.coreStatus()`
- `await client.core_ipc()` / `await client.coreIpc()`
- `await client.core_managers()` / `await client.coreManagers()`
- `await client.core_databases()` / `await client.coreDatabases()`
- `await client.core_database_status(db)` / `await client.coreDatabaseStatus(db)`
- `await client.core_database_schema_version(db)` / `await client.coreDatabaseSchemaVersion(db)`
- `await client.set_core_database_schema_version(db, schemaVersion)` / `await client.setCoreDatabaseSchemaVersion(db, schemaVersion)`

### Database (`DB` / `LioranDB`)

- `col = db.collection(name)`
- `await db.list_collections()` / `await db.listCollections()`
- `await db.create_collection(name)` / `await db.createCollection(name)`
- `await db.drop_collection(name)` / `await db.dropCollection(name)`
- `await db.rename_collection(old, new)` / `await db.renameCollection(oldName, newName)`
- `await db.stats()`
- `await db.compact_all()` / `await db.compactAll()`
- `await db.get_schema_version()` / `await db.getSchemaVersion()`
- `await db.set_schema_version(schema_version)` / `await db.setSchemaVersion(schemaVersion)`
- `await db.apply_migrations(target_version, migrations)` / `await db.applyMigrations(targetVersion, migrations)`
- `await db.rotate_encryption_key(new_key)` / `await db.rotateEncryptionKey(newKey)`
- `await db.compact_collection(name)` / `await db.compactCollection(name)`
- `await db.create_index(collection, field, unique=False)` / `await db.createIndex(collection, field, options={"unique": True})`
- `await db.create_text_index(collection, field, options={...})` / `await db.createTextIndex(collection, field, options={...})`
- `await db.list_indexes(collection)` / `await db.listIndexes(collection)`
- `await db.drop_index(collection, field)` / `await db.dropIndex(collection, field)`
- `await db.drop_text_index(collection, field)` / `await db.dropTextIndex(collection, field)`
- `await db.rebuild_index(collection, field)` / `await db.rebuildIndex(collection, field)`
- `await db.rebuild_text_index(collection, field)` / `await db.rebuildTextIndex(collection, field)`
- `await db.rebuild_indexes(collection)` / `await db.rebuildIndexes(collection)`
- `await db.get_collection_options(collection)` / `await db.getCollectionOptions(collection)`
- `await db.set_collection_date_option(collection, date)` / `await db.setCollectionDateOption(collection, date)`
- `await db.explain(collection, query={}, options=None)`
- `await db.transaction([...])` or `await db.transaction(async_fn)` (matches the TS "ops or function" pattern)
- `await db.get_credentials()` / `await db.getCredentials()`
- `await db.set_credentials(username, password)` / `await db.setCredentials({"username": "...", "password": "..."})`
- `await db.get_connection_string()` / `await db.getConnectionString()`

### Collection (`Collection` / `LioranCollection`)

- `await col.insert_one(doc)` / `await col.insertOne(doc)`
- `await col.insert_many(docs)` / `await col.insertMany(docs)`
- `await col.insert_many_stream(docs)` / `await col.insertManyStream(docs)`
- `await col.find(filter={}, options=None)`
- `await col.find_one(filter={}, options=None)` / `await col.findOne(filter={}, options=None)`
- `await col.update_one(filter, update, options=None)` / `await col.updateOne(filter, update, options=None)`
- `await col.update_many(filter, update)` / `await col.updateMany(filter, update)`
- `await col.delete_one(filter)` / `await col.deleteOne(filter)`
- `await col.delete_many(filter)` / `await col.deleteMany(filter)`
- `await col.count(filter={})`
- `await col.count_documents(filter={})` / `await col.countDocuments(filter={})`
- `await col.aggregate(pipeline=[])`
- `await col.list_indexes()` / `await col.listIndexes()`
- `await col.create_index(field, unique=False)` / `await col.createIndex(field, options={"unique": True})`
- `await col.create_text_index(field, options={...})` / `await col.createTextIndex(field, options={...})`
- `await col.drop_index(field)` / `await col.dropIndex(field)`
- `await col.drop_text_index(field)` / `await col.dropTextIndex(field)`
- `await col.rebuild_index(field)` / `await col.rebuildIndex(field)`
- `await col.rebuild_text_index(field)` / `await col.rebuildTextIndex(field)`
- `await col.rebuild_indexes()` / `await col.rebuildIndexes()`
- `await col.explain(query={}, options=None)`
- `await col.get_options()` / `await col.getOptions()`
- `await col.set_date_option(date)` / `await col.setDateOption(date)`
- `await col.stats()`
- `await col.compact()`
- `await col.get_doc_migrations()` / `await col.getDocMigrations()`
- `await col.set_doc_migrations(config)` / `await col.setDocMigrations(config)`
- `await col.test_doc_migration(doc)` / `await col.testDocMigration(doc)`

## Errors

All non-2xx responses raise `liorandb_driver.HttpError` which includes:
- `status` (HTTP status code)
- `data` (parsed JSON if possible, otherwise text)

## Publishing to PyPI

This repo is set up for PEP 517 builds via `pyproject.toml`.

```bash
python -m pip install -U build twine
python -m build
python -m twine upload dist/*
```
