Skip to main content

SQLite ORM using Pydantic models - simple, type-safe, high-performance SQLite operations with connection pooling

Project description

wsqlite

SQLite ORM using Pydantic models - simple, type-safe, high-performance SQLite operations

PyPI version Python versions License

High-level Python ORM library that provides a clean, type-safe interface for SQLite database operations using Pydantic models for schema definition.

๐Ÿš€ Key Features

  • ๐Ÿ”— Pydantic Integration - Define database schema using Pydantic v2 models
  • ๐Ÿ”„ Auto Table Creation - Tables created/synchronized automatically with model changes
  • โšก Connection Pooling - High-performance thread-safe connection pool with WAL mode
  • ๐Ÿ“ CRUD Operations - Simple insert, get, update, delete methods
  • ๐Ÿ” Column Sync - Automatically adds new columns when model changes
  • ๐Ÿ”’ Constraints Support - Primary Key, UNIQUE, NOT NULL, Foreign Keys
  • ๐Ÿ›ก๏ธ Type Safety - Full type hints and Pydantic validation
  • โšก Async Support - Full async/await for high-performance applications
  • ๐Ÿ”จ Query Builder - Safe query construction with SQL injection prevention
  • ๐Ÿ“Š Advanced Query Builder - JOINs, GROUP BY, HAVING, UNION support
  • ๐Ÿ”„ Migrations - Version-based schema migration system
  • ๐Ÿงช Stress Testing - Built-in benchmarks and performance testing
  • ๐Ÿ’ป CLI Tool - Command-line interface for common operations
  • ๐Ÿ† Battle Tested - Comprehensive unit and integration tests

๐Ÿ“Š Performance

๐Ÿ† wSQLite (Pool) Benchmark Results:
   Ops/sec: ~5,000+ insertions/second
   Latency: ~0.2ms average
   Memory:  <10MB overhead

๐Ÿ“ฆ Installation

pip install wsqlite

Development installation with dev tools:

pip install -e ".[dev]"

With benchmarking tools:

pip install -e ".[benchmark,stress]"

๐Ÿš€ Quick Start

Basic Usage

from pydantic import BaseModel
from wsqlite import WSQLite

class User(BaseModel):
    id: int
    name: str
    email: str

# Create database - table is created automatically
db = WSQLite(User, "database.db")

# Insert data
db.insert(User(id=1, name="John", email="john@example.com"))

# Query data
users = db.get_all()
john = db.get_by_field(name="John")

# Update and delete
db.update(1, User(id=1, name="Johnny", email="johnny@example.com"))
db.delete(1)

With Connection Pooling

from wsqlite import WSQLite

db = WSQLite(User, "database.db", pool_size=20, min_pool_size=2)

Async Operations

import asyncio
from wsqlite import WSQLite

async def main():
    db = WSQLite(User, "database.db")
    await db.insert_async(User(id=1, name="John", email="john@example.com"))
    users = await db.get_all_async()

asyncio.run(main())

Advanced Query Builder

from wsqlite.builders import AdvancedQueryBuilder

results = (
    AdvancedQueryBuilder("users")
    .select("id", "name", "email")
    .join("orders", "users.id = orders.user_id", "LEFT")
    .where("status", "=", "active")
    .group_by("users.id")
    .having("COUNT(orders.id)", ">", 5)
    .order_by("users.name")
    .limit(100)
    .execute(conn)
)

Database Migrations

from wsqlite import WSQLite
from wsqlite.migrations import MigrationManager

manager = MigrationManager("app.db")

@manager.migration(1, "Create initial schema")
def m1(ctx):
    ctx.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)")

manager.migrate_up()

๐Ÿงช Testing

Run tests:

pytest

Run stress tests:

python -m stress_test.run --scenario concurrent --records 100000 --threads 50

Run benchmarks:

python -m benchmark.run --all --report html

๐Ÿ“ Project Structure

wsqlite/
โ”œโ”€โ”€ src/wsqlite/           # Main library
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”œโ”€โ”€ core/             # Core database operations
โ”‚   โ”‚   โ”œโ”€โ”€ connection.py # Connection management
โ”‚   โ”‚   โ”œโ”€โ”€ pool.py       # Connection pooling
โ”‚   โ”‚   โ”œโ”€โ”€ repository.py # CRUD operations
โ”‚   โ”‚   โ””โ”€โ”€ sync.py       # Table sync
โ”‚   โ”œโ”€โ”€ builders/          # Query builders
โ”‚   โ”œโ”€โ”€ exceptions.py      # Custom exceptions
โ”‚   โ”œโ”€โ”€ migrations.py      # Schema migrations
โ”‚   โ”œโ”€โ”€ types/            # SQL type mapping
โ”‚   โ”œโ”€โ”€ validators.py      # Type validation
โ”‚   โ””โ”€โ”€ cli/              # CLI tool
โ”œโ”€โ”€ examples/              # Usage examples
โ”œโ”€โ”€ test/                 # Test suite
โ”œโ”€โ”€ stress_test/          # Stress testing
โ”œโ”€โ”€ benchmark/            # Benchmarking
โ””โ”€โ”€ pyproject.toml

๐ŸŽฏ Advanced Features

Auto-incrementing IDs

To define an auto-incrementing primary key, use Optional[int] with Field(description="primary autoincrement"):

from typing import Optional
from pydantic import BaseModel, Field

class User(BaseModel):
    id: Optional[int] = Field(None, description="primary autoincrement")
    name: str

# When inserting, skip the id field or set it to None
db.insert(User(name="Alice"))

Composite Unique Constraints

To define a unique constraint across multiple columns, use unique:group_name in the field descriptions:

class User(BaseModel):
    name: str = Field(..., description="unique:name_lastname")
    lastname: str = Field(..., description="unique:name_lastname")

# (name, lastname) must be unique together

Foreign Keys

To define a foreign key relationship, use references:table.column:

class Book(BaseModel):
    title: str
    author_id: int = Field(..., description="references:author.id")

# Foreign key enforcement is enabled by default

Connection Pool

from wsqlite import ConnectionPool, WSQLite

pool = ConnectionPool("app.db", min_size=2, max_size=20)
db = WSQLite(User, "app.db", pool_size=10)

# Use pool directly
with pool.connection() as conn:
    cursor = conn.execute("SELECT * FROM users")

Transactions

from wsqlite import WSQLite

db = WSQLite(User, "database.db")

# Simple transaction
db.execute_transaction([
    ("INSERT INTO users VALUES (?, ?)", (1, "John")),
    ("INSERT INTO orders VALUES (?, ?)", (1, 100)),
])

# Function-based transaction
result = db.with_transaction(lambda txn: txn.execute("SELECT COUNT(*) FROM users"))

Bulk Operations

# Bulk insert
users = [User(id=i, name=f"User{i}", email=f"user{i}@test.com") for i in range(10000)]
db.insert_many(users)

# Bulk update
updates = [(User(id=i, name=f"Updated{i}", email=f"updated{i}@test.com"), i) for i in range(100)]
db.update_many(updates)

๐Ÿ”ง Configuration

Environment Variables

  • WSQLITE_DB_PATH - Default database path
  • WSQLITE_LOG_LEVEL - Logging level (default: INFO)

Pool Configuration

db = WSQLite(
    User, 
    "database.db",
    pool_size=20,      # Max connections
    min_pool_size=2,   # Min connections
    use_pool=True       # Enable pooling
)

๐Ÿ“ˆ Version History

  • v1.2.0 - 90%+ test coverage, async connection pool, comprehensive testing suite
  • v1.1.0 - Connection pooling, advanced query builder, migrations, stress testing
  • v1.0.0 - Initial stable release

๐Ÿงช Test Coverage

317 tests | 79% code coverage

Run with coverage:

pytest --cov=wsqlite --cov-report=term-missing

๐Ÿ“ License

MIT License - see LICENSE file.

๐Ÿ‘ค Author

William Steve Rodriguez Villamizar

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

wsqlite-1.2.2.tar.gz (22.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

wsqlite-1.2.2-py3-none-any.whl (18.9 kB view details)

Uploaded Python 3

File details

Details for the file wsqlite-1.2.2.tar.gz.

File metadata

  • Download URL: wsqlite-1.2.2.tar.gz
  • Upload date:
  • Size: 22.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for wsqlite-1.2.2.tar.gz
Algorithm Hash digest
SHA256 85695c830e58686ab74ddc3f98308d0774a0ebecf859e5d8fc33bbb477309b2f
MD5 fd39cbcba6351a05935d31d9a3edf26e
BLAKE2b-256 e05e5e3bf2325e41c32f286007edef3e21cc5319771230526780846eb193b698

See more details on using hashes here.

File details

Details for the file wsqlite-1.2.2-py3-none-any.whl.

File metadata

  • Download URL: wsqlite-1.2.2-py3-none-any.whl
  • Upload date:
  • Size: 18.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for wsqlite-1.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 78875fe7c8b5480b12d59e7bbaedd9ae3cd547330cec910d1e854187f0529a96
MD5 c70fa4a6b931cbcca33aa08d77bb9e7d
BLAKE2b-256 f336349dcfdedcd68c713caa21d8c5106fedf4b60d14dd7e3b09eb7be0c12f50

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page