-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
update readme.md
- Loading branch information
Showing
1 changed file
with
123 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,106 +1,168 @@ | ||
# QuestDB Python Client | ||
# QuestDB Python Library | ||
|
||
This is an open-source Python library for interacting with QuestDB, a high-performance, open-source SQL database designed to process time series data. This client provides an easy-to-use interface for querying and writing data to QuestDB from Python applications. | ||
A robust, strongly-typed Python library for interacting with QuestDB, providing an easy-to-use interface for querying, writing data, and managing logs. | ||
|
||
## Features | ||
|
||
- Asynchronous and synchronous query execution | ||
- Write single or multiple messages to QuestDB | ||
- Buffer writes for improved performance | ||
- Convert query results to Pandas DataFrames | ||
- Type conversion and parsing of query results | ||
- Support for both HTTP and TCP interfaces | ||
- Asynchronous and synchronous query support | ||
- Strongly-typed data structures | ||
- Easy data insertion with automatic flushing | ||
- Pandas DataFrame integration | ||
- Built-in logging handler for QuestDB | ||
- Comprehensive test coverage | ||
|
||
## Installation | ||
|
||
You can install the QuestDB Python Client using pip: | ||
Install the QuestDB Python library using pip: | ||
|
||
```bash | ||
pip install py-questdb | ||
``` | ||
|
||
## Quick Start | ||
|
||
Here's a simple example to get you started: | ||
|
||
```python | ||
import asyncio | ||
from questdb_python_client import QuestDB | ||
|
||
async def main(): | ||
# Connect to QuestDB | ||
db = QuestDB(host="localhost", port=9000) | ||
from py_questdb import QuestDB | ||
|
||
# Write some data | ||
await db.write( | ||
table_name="sensors", | ||
symbols={"location": "room1"}, | ||
columns={"temperature": 22.5, "humidity": 60}, | ||
at=datetime.now() | ||
) | ||
# Initialize QuestDB client | ||
db = QuestDB(host="localhost", port=9000) | ||
|
||
# Query data | ||
async for row in db.query("SELECT * FROM sensors ORDER BY timestamp DESC LIMIT 10"): | ||
print(row) | ||
# Write data | ||
db.write({ | ||
"table_name": "my_table", | ||
"symbols": {"symbol_column": "AAPL"}, | ||
"columns": {"number_column": 42, "string_column": "Hello, QuestDB!"}, | ||
"at": datetime.now() | ||
}) | ||
|
||
# Query data as a DataFrame | ||
df = await db.query_df("SELECT * FROM sensors WHERE location = 'room1'") | ||
print(df) | ||
# Query data (synchronous) | ||
for row in db.query_sync("SELECT * FROM my_table"): | ||
print(row) | ||
|
||
await db.close() | ||
# Query data (asynchronous) | ||
async for row in db.query("SELECT * FROM my_table"): | ||
print(row) | ||
|
||
asyncio.run(main()) | ||
# Query data as Pandas DataFrame | ||
df = db.query_df_sync("SELECT * FROM my_table") | ||
print(df) | ||
``` | ||
|
||
## Usage | ||
## Detailed Usage | ||
|
||
### Connecting to QuestDB | ||
### Initialization | ||
|
||
```python | ||
from questdb_python_client import QuestDB | ||
from py_questdb import QuestDB | ||
|
||
# For HTTP interface | ||
db = QuestDB(host="localhost", port=9000) | ||
# Default connection | ||
db = QuestDB() | ||
|
||
# For TCP interface | ||
db = QuestDB(host="localhost", port=9009) | ||
# Custom connection | ||
db = QuestDB(host="questdb.example.com", port=9000, username="user", password="pass") | ||
``` | ||
|
||
### Writing Data | ||
|
||
```python | ||
# Write a single message | ||
db.write( | ||
table_name="sensors", | ||
symbols={"location": "room1"}, | ||
columns={"temperature": 22.5, "humidity": 60}, | ||
at=datetime.now() | ||
) | ||
|
||
# Write multiple messages | ||
messages = [ | ||
QuestMessage(table_name="sensors", symbols={"location": "room1"}, columns={"temperature": 22.5}, at=datetime.now()), | ||
QuestMessage(table_name="sensors", symbols={"location": "room2"}, columns={"temperature": 23.1}, at=datetime.now()) | ||
] | ||
db.write_iter(messages) | ||
from datetime import datetime | ||
from py_questdb.db_types import QuestDBFields | ||
|
||
# Single write with auto-flush | ||
db.write({ | ||
"table_name": "sensors", | ||
"symbols": {"location": "NYC"}, | ||
"columns": {"temperature": 25.5, "humidity": 60}, | ||
"at": datetime.now() | ||
}) | ||
|
||
# Buffer multiple writes | ||
db.buffer_write({ | ||
"table_name": "sensors", | ||
"symbols": {"location": "LA"}, | ||
"columns": {"temperature": 28.0, "humidity": 55}, | ||
"at": datetime.now() | ||
}) | ||
|
||
# Manually flush buffered writes | ||
db.flush() | ||
|
||
# Write using custom message class | ||
class SensorData(msgspec.Struct): | ||
location: str | ||
temperature: float | ||
humidity: int | ||
timestamp: datetime | ||
|
||
def to_quest_db_format(self) -> QuestDBFields: | ||
return { | ||
"table_name": "sensors", | ||
"symbols": {"location": self.location}, | ||
"columns": {"temperature": self.temperature, "humidity": self.humidity}, | ||
"at": self.timestamp | ||
} | ||
|
||
sensor_data = SensorData(location="SF", temperature=22.5, humidity=65, timestamp=datetime.now()) | ||
db.write(sensor_data) | ||
``` | ||
|
||
### Querying Data | ||
|
||
```python | ||
# Synchronous query | ||
for row in db.query_sync("SELECT * FROM sensors WHERE location = 'NYC'"): | ||
print(f"Temperature: {row['temperature']}, Humidity: {row['humidity']}") | ||
|
||
# Asynchronous query | ||
async for row in db.query("SELECT * FROM sensors WHERE location = 'room1'"): | ||
print(row) | ||
async for row in db.query("SELECT * FROM sensors WHERE location = 'LA'"): | ||
print(f"Temperature: {row['temperature']}, Humidity: {row['humidity']}") | ||
|
||
# Synchronous query | ||
for row in db.query_sync("SELECT * FROM sensors WHERE location = 'room1'"): | ||
print(row) | ||
# Query into Pandas DataFrame | ||
df = db.query_df_sync("SELECT * FROM sensors") | ||
print(df.describe()) | ||
|
||
# Query as DataFrame | ||
df = await db.query_df("SELECT * FROM sensors WHERE location = 'room1'") | ||
print(df) | ||
# Query with type hinting | ||
class SensorReading(msgspec.Struct): | ||
location: str | ||
temperature: float | ||
humidity: int | ||
|
||
async for reading in db.query("SELECT * FROM sensors", into_type=SensorReading): | ||
print(f"Location: {reading.location}, Temp: {reading.temperature}°C, Humidity: {reading.humidity}%") | ||
``` | ||
|
||
### Logging | ||
|
||
```python | ||
import logging | ||
from py_questdb import QuestDB | ||
from py_questdb.log_handler import QuestDBLogHandler | ||
|
||
# Set up QuestDB logging | ||
questdb_client = QuestDB() | ||
handler = QuestDBLogHandler(questdb_client=questdb_client) | ||
logger = logging.getLogger() | ||
logger.addHandler(handler) | ||
logger.setLevel(logging.INFO) | ||
|
||
# Log messages | ||
logger.info("System started") | ||
logger.warning("Low disk space") | ||
logger.error("Connection failed", exc_info=True) | ||
``` | ||
|
||
## Testing | ||
|
||
Run the test suite using pytest: | ||
|
||
```bash | ||
pytest | ||
``` | ||
|
||
## Contributing | ||
|
||
Contributions are welcome! Please feel free to submit a Pull Request. | ||
|
||
## License | ||
|
||
This project is licensed under the [MIT License](LICENSE). |