{"id":37074022,"url":"https://github.com/abilian/kenobix","last_synced_at":"2026-01-14T08:43:06.041Z","repository":{"id":329161102,"uuid":"1074392701","full_name":"abilian/kenobix","owner":"abilian","description":"Simple sqlite-based document database and ODM","archived":false,"fork":false,"pushed_at":"2026-01-12T19:11:06.000Z","size":1289,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-12T22:53:14.457Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/abilian.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-11T17:44:28.000Z","updated_at":"2026-01-12T19:11:04.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/abilian/kenobix","commit_stats":null,"previous_names":["abilian/kenobix"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/abilian/kenobix","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abilian%2Fkenobix","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abilian%2Fkenobix/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abilian%2Fkenobix/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abilian%2Fkenobix/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/abilian","download_url":"https://codeload.github.com/abilian/kenobix/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abilian%2Fkenobix/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28414691,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T08:38:59.149Z","status":"ssl_error","status_checked_at":"2026-01-14T08:38:43.588Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-14T08:43:05.515Z","updated_at":"2026-01-14T08:43:06.026Z","avatar_url":"https://github.com/abilian.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# KenobiX\n\n**High-Performance Minimal Document Database** • **SQLite3-Powered** • **One Dependency (cattrs)**\n\nKenobiX is a document database with proper SQLite3 JSON optimization, delivering faster searches and faster updates compared to basic implementations.\n\nBased on [KenobiDB](https://github.com/patx/kenobi) by Harrison Erd, enhanced with generated column indexes and optimized concurrency. (\"KenobiX\" = \"Kenobi + indeX\").\n\n\u003c!-- toc --\u003e\n\n- [Why KenobiX?](#why-kenobix)\n- [Features](#features)\n- [Command-Line Interface](#command-line-interface)\n- [Performance Benchmarks](#performance-benchmarks)\n- [ACID Compliance](#acid-compliance)\n- [Documentation](#documentation)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Object Document Mapper (ODM)](#object-document-mapper-odm)\n  * [Installation](#installation-1)\n  * [Usage](#usage)\n  * [ODM Features](#odm-features)\n  * [ODM Transaction Support](#odm-transaction-support)\n- [Multi-Collection Support](#multi-collection-support)\n  * [Quick Example](#quick-example)\n  * [Benefits](#benefits)\n  * [ODM with Collections](#odm-with-collections)\n- [ODM Relationships](#odm-relationships)\n  * [Quick Example](#quick-example-1)\n  * [Many-to-Many Relationships](#many-to-many-relationships)\n  * [Relationship Features](#relationship-features)\n- [When to Use KenobiX](#when-to-use-kenobix)\n  * [Perfect For:](#perfect-for)\n  * [Consider Alternatives For:](#consider-alternatives-for)\n- [When to Use Transactions](#when-to-use-transactions)\n  * [Use Transactions For:](#use-transactions-for)\n  * [Auto-commit is Fine For:](#auto-commit-is-fine-for)\n- [Index Selection Strategy](#index-selection-strategy)\n- [API Documentation](#api-documentation)\n  * [Initialization](#initialization)\n  * [CRUD Operations](#crud-operations)\n  * [Transaction Operations](#transaction-operations)\n  * [Advanced Operations](#advanced-operations)\n- [Performance Tips](#performance-tips)\n- [Migration from KenobiDB](#migration-from-kenobidb)\n- [Requirements](#requirements)\n- [Testing](#testing)\n- [Benchmarking](#benchmarking)\n  * [ODM Performance](#odm-performance)\n- [Credits](#credits)\n- [License](#license)\n- [Contributing](#contributing)\n- [Links](#links)\n- [Changelog](#changelog)\n\n\u003c!-- tocstop --\u003e\n\n## Why KenobiX?\n\n```python\nfrom kenobix import KenobiX\n\n# Create database with indexed fields\ndb = KenobiX('app.db', indexed_fields=['user_id', 'email', 'status'])\n\n# Lightning-fast queries (0.01ms vs 2.5ms unindexed)\nusers = db.search('email', 'alice@example.com')\n\n# Massively faster updates (665x improvement on complex documents)\ndb.update('user_id', 123, {'status': 'active'})\n```\n\n## Features\n\n- **ODM Relationships** - ForeignKey, RelatedSet, and ManyToMany support for managing relationships between models\n- **Multi-Collection Support** - Organize data into separate collections (like MongoDB or SQL tables)\n- **Full ACID Transactions** - Context manager API with savepoints for nested transactions\n- **Automatic Index Usage** - Queries automatically use indexes when available, fall back to json_extract\n- **VIRTUAL Generated Columns** - Minimal storage overhead (~7-20% depending on document complexity)\n- **Thread-Safe** - No RLock on reads, SQLite handles concurrency with WAL mode\n- **MongoDB-like API** - Familiar insert/search/update operations\n- **Optional ODM Layer** - Type-safe dataclass-based models with per-model collections\n- **Cursor Pagination** - Efficient pagination for large datasets\n- **Query Analysis** - Built-in `explain()` for optimization\n- **Zero Runtime Dependencies** - Only Python stdlib (cattrs optional for ODM)\n- **Command-Line Interface** - Inspect and dump databases from the terminal\n\n## Command-Line Interface\n\nKenobiX includes a CLI tool for database inspection and data export:\n\n```bash\n# Dump entire database to JSON\nkenobix dump -d myapp.db\n\n# Dump specific table to file\nkenobix dump -d myapp.db -t users -o users.json\n\n# Show database info\nkenobix info -d myapp.db\n\n# Show info for a specific table\nkenobix info -d myapp.db -t users\n\n# Detailed info with column definitions\nkenobix info -d myapp.db -vv\n```\n\n**Database specification** (in order of precedence):\n1. `-d/--database` option: `kenobix dump -d myapp.db`\n2. Environment variable: `KENOBIX_DATABASE=myapp.db kenobix dump`\n3. Auto-detection: single `.db` file in current directory\n\n**Options work before or after command:**\n```bash\nkenobix -d myapp.db dump -t users    # -d before command\nkenobix dump -d myapp.db -t users    # -d after command\n```\n\n**Available commands:**\n\n| Command | Description |\n|---------|-------------|\n| `dump` | Export database contents as JSON |\n| `info` | Display database information |\n\n**Common options:**\n\n| Option | Description |\n|--------|-------------|\n| `-d, --database` | Path to database file |\n| `-v, --verbose` | Increase verbosity (repeatable: `-v`, `-vv`) |\n| `-q, --quiet` | Suppress non-essential output |\n\n**Dump-specific options:**\n\n| Option | Description |\n|--------|-------------|\n| `-o, --output` | Write to file instead of stdout |\n| `-t, --table` | Dump only specified table |\n| `--compact` | Output minified JSON |\n\n**Info-specific options:**\n\n| Option | Description |\n|--------|-------------|\n| `-t, --table` | Show detailed info with pseudo-schema for specified table |\n\n**Example: Single table info with pseudo-schema**\n\n```bash\n$ kenobix info -d myapp.db -t users\nDatabase: myapp.db\n\nTable: users\nRecords: 1,234\nIndexed fields: email, name\n\nPseudo-schema (inferred from 100 records):\n  active: boolean (95% present)\n  age: integer (80% present)\n  email: string [indexed]\n  metadata: object (15% present)\n  name: string [indexed]\n  tags: array (30% present)\n```\n\n## Performance Benchmarks\n\nReal-world measurements on a 10,000 document dataset:\n\n| Operation | Without Indexes | With Indexes | Speedup |\n|-----------|----------------|--------------|---------|\n| Exact search | 6.52ms | 0.009ms | **724x faster** |\n| Update 100 docs | 1.29s | 15.55ms | **83x faster** |\n| Range-like queries | 2.96ms | 0.52ms | **5.7x faster** |\n\n**Document complexity matters:** More complex documents see even greater benefits (up to 665x for very complex documents).\n\nSee `benchmarks/` for detailed performance analysis.\n\n## ACID Compliance\n\n**KenobiX provides full ACID transaction support** backed by SQLite's proven transaction engine:\n\n- ✅ **Atomicity** - All-or-nothing execution with automatic rollback on errors\n- ✅ **Consistency** - Data integrity maintained across all operations\n- ✅ **Isolation** - Read Committed isolation prevents dirty reads\n- ✅ **Durability** - Committed data persists through crashes (WAL mode)\n\n**25/25 comprehensive ACID tests passing (100%)** - See [ACID Compliance](docs/dev/acid-compliance.md) for proof.\n\n```python\n# Banking transfer with automatic rollback on error\nwith db.transaction():\n    db.update('account_id', 'A1', {'balance': 900})  # -100\n    db.update('account_id', 'A2', {'balance': 1100}) # +100\n    # Both succeed or both fail - guaranteed atomicity\n```\n\n## Documentation\n\n- **[Getting Started](docs/index.md)** - Quick start guide\n- **[Relationships Guide](docs/relationships.md)** - ForeignKey, RelatedSet, and ManyToMany relationships\n- **[Collections Guide](docs/collections.md)** - Multi-collection support and usage\n- **[Transactions](docs/transactions.md)** - Full ACID transaction API guide\n- **[ACID Compliance](docs/dev/acid-compliance.md)** - Comprehensive ACID test results\n- **[ODM Guide](docs/odm.md)** - Complete ODM documentation with examples\n- **[Performance Guide](docs/performance.md)** - Benchmarks and optimization tips\n- **[API Reference](docs/api-reference.md)** - Full API documentation\n\n## Installation\n\n```bash\npip install kenobix\n```\n\nOr install from source:\n\n```bash\ngit clone https://github.com/yourusername/kenobix\ncd kenobix\npip install -e .\n```\n\n## Quick Start\n\n```python\nfrom kenobix import KenobiX\n\n# Initialize with indexed fields for best performance\ndb = KenobiX('myapp.db', indexed_fields=['user_id', 'email', 'status'])\n\n# Insert documents\ndb.insert({'user_id': 1, 'email': 'alice@example.com', 'status': 'active'})\ndb.insert_many([\n    {'user_id': 2, 'email': 'bob@example.com', 'status': 'active'},\n    {'user_id': 3, 'email': 'carol@example.com', 'status': 'inactive'}\n])\n\n# Fast indexed searches\nusers = db.search('status', 'active')  # Uses index!\nuser = db.search('email', 'alice@example.com')  # Uses index!\n\n# Non-indexed fields still work (slower but functional)\ntagged = db.search('tags', 'python')  # Falls back to json_extract\n\n# Multi-field optimized search\nresults = db.search_optimized(status='active', user_id=1)\n\n# Update operations are massively faster\ndb.update('user_id', 1, {'last_login': '2025-01-15'})\n\n# Efficient cursor-based pagination\nresult = db.all_cursor(limit=100)\ndocuments = result['documents']\nif result['has_more']:\n    next_page = db.all_cursor(after_id=result['next_cursor'], limit=100)\n\n# Query optimization\nplan = db.explain('search', 'email', 'test@example.com')\nprint(plan)  # Shows if index is being used\n\n# Transactions for ACID guarantees\nwith db.transaction():\n    # All operations succeed or all fail together\n    db.insert({'user_id': 4, 'email': 'dave@example.com', 'balance': 1000})\n    db.update('user_id', 1, {'balance': 900})  # Transfer -100\n    db.update('user_id', 4, {'balance': 1100}) # Transfer +100\n    # Automatic commit on success, rollback on error\n\n# Manual transaction control\ndb.begin()\ntry:\n    db.insert({'user_id': 5, 'email': 'eve@example.com'})\n    db.commit()\nexcept Exception:\n    db.rollback()\n    raise\n\n# Nested transactions with savepoints\nwith db.transaction():\n    db.insert({'status': 'processing'})\n    try:\n        with db.transaction():  # Nested - uses savepoint\n            db.insert({'status': 'temporary'})\n            raise ValueError(\"Rollback nested only\")\n    except ValueError:\n        pass  # Inner transaction rolled back\n    db.insert({'status': 'completed'})\n    # Outer transaction commits both 'processing' and 'completed'\n```\n\n## Object Document Mapper (ODM)\n\nKenobiX includes an optional ODM layer for type-safe, Pythonic document operations using dataclasses.\n\n### Installation\n\n```bash\npip install kenobix[odm]  # Includes cattrs for serialization\n```\n\n### Usage\n\n```python\nfrom dataclasses import dataclass\nfrom typing import List\nfrom kenobix import KenobiX, Document\n\n# Define your models\n@dataclass\nclass User(Document):\n    name: str\n    email: str\n    age: int\n    active: bool = True\n\n@dataclass\nclass Post(Document):\n    title: str\n    content: str\n    author_id: int\n    tags: List[str]\n    published: bool = False\n\n# Setup\ndb = KenobiX('app.db', indexed_fields=['email', 'name', 'author_id'])\nDocument.set_database(db)\n\n# Create\nuser = User(name=\"Alice\", email=\"alice@example.com\", age=30)\nuser.save()  # Returns user with _id set\n\n# Read\nalice = User.get(email=\"alice@example.com\")\nusers = User.filter(age=30)\nall_users = User.all(limit=100)\n\n# Update\nalice.age = 31\nalice.save()\n\n# Delete\nalice.delete()\n\n# Bulk operations\nUser.insert_many([user1, user2, user3])\nUser.delete_many(active=False)\n\n# Count\ntotal = User.count()\nactive_count = User.count(active=True)\n```\n\n### ODM Features\n\n- **Type Safety** - Full type hints with autocomplete support\n- **Automatic Serialization** - Uses cattrs for nested structures\n- **Indexed Queries** - Automatically uses KenobiX indexes\n- **Bulk Operations** - Efficient insert_many, delete_many\n- **Familiar API** - Similar to MongoDB ODMs (ODMantic, MongoEngine)\n- **Zero Boilerplate** - Just use @dataclass decorator\n\nSee `examples/odm_example.py` for complete examples.\n\n### ODM Transaction Support\n\nThe ODM layer fully supports transactions:\n\n```python\n# Context manager\nwith User.transaction():\n    alice = User(name=\"Alice\", email=\"alice@example.com\", age=30)\n    bob = User(name=\"Bob\", email=\"bob@example.com\", age=25)\n    alice.save()\n    bob.save()\n    # Both saved atomically\n\n# Manual control\nUser.begin()\ntry:\n    user = User.get(email=\"alice@example.com\")\n    user.age = 31\n    user.save()\n    User.commit()\nexcept Exception:\n    User.rollback()\n    raise\n```\n\nSee [docs/transactions.md](docs/transactions.md) for complete transaction documentation.\n\n## Multi-Collection Support\n\nKenobiX supports organizing data into multiple collections (similar to MongoDB collections or SQL tables). Each collection has its own table, indexes, and schema within a single database file.\n\n### Quick Example\n\n```python\nfrom kenobix import KenobiX\n\ndb = KenobiX('myapp.db')\n\n# Create collections with independent indexes\nusers = db.collection('users', indexed_fields=['user_id', 'email'])\norders = db.collection('orders', indexed_fields=['order_id', 'user_id'])\nproducts = db.collection('products', indexed_fields=['product_id', 'category'])\n\n# Dictionary-style access\ndb['users'].insert({'user_id': 1, 'name': 'Alice', 'email': 'alice@example.com'})\ndb['orders'].insert({'order_id': 101, 'user_id': 1, 'amount': 99.99})\n\n# Each collection is completely isolated\nusers = db['users'].all(limit=100)\norders = db['orders'].all(limit=100)\n\n# Transactions work across collections\nwith db.transaction():\n    db['users'].insert({'user_id': 2, 'name': 'Bob'})\n    db['orders'].insert({'order_id': 102, 'user_id': 2, 'amount': 149.99})\n```\n\n### Benefits\n\n- **Better Organization**: Each entity type in its own collection\n- **Improved Performance**: Smaller tables with focused indexes\n- **Complete Isolation**: No mixing of different document types\n- **Independent Indexes**: Each collection can have different indexed fields\n- **Type Safety**: Cleaner queries without type field filtering\n\n### ODM with Collections\n\nThe ODM layer automatically uses collections:\n\n```python\nfrom dataclasses import dataclass\nfrom kenobix.odm import Document\n\n@dataclass\nclass User(Document):\n    class Meta:\n        collection_name = \"users\"\n        indexed_fields = [\"user_id\", \"email\"]\n\n    user_id: int\n    name: str\n    email: str\n\n@dataclass\nclass Order(Document):\n    class Meta:\n        collection_name = \"orders\"\n        indexed_fields = [\"order_id\", \"user_id\"]\n\n    order_id: int\n    user_id: int\n    amount: float\n\n# Each model uses its own collection\nuser = User(user_id=1, name='Alice', email='alice@example.com')\nuser.save()  # -\u003e users collection\n\norder = Order(order_id=101, user_id=1, amount=99.99)\norder.save()  # -\u003e orders collection\n```\n\nSee [docs/collections.md](docs/collections.md) for complete documentation and `examples/collections_example.py` for real-world examples.\n\n## ODM Relationships\n\nKenobiX provides transparent relationship support for modeling connections between documents with ForeignKey, RelatedSet, and ManyToMany relationships.\n\n### Quick Example\n\n```python\nfrom dataclasses import dataclass, field\nfrom kenobix import KenobiX, ForeignKey, RelatedSet, ManyToMany\nfrom kenobix.odm import Document\n\ndb = KenobiX('myapp.db')\nDocument.set_database(db)\n\n# Define models with relationships\n@dataclass\nclass User(Document):\n    class Meta:\n        collection_name = \"users\"\n        indexed_fields = [\"user_id\"]\n\n    user_id: int\n    name: str\n\n@dataclass\nclass Order(Document):\n    class Meta:\n        collection_name = \"orders\"\n        indexed_fields = [\"order_id\", \"user_id\"]\n\n    order_id: int\n    user_id: int\n    amount: float\n\n    # Many-to-one: many orders belong to one user\n    user: ForeignKey[User] = field(\n        default=ForeignKey(\"user_id\", User),\n        init=False,\n        repr=False,\n        compare=False\n    )\n\n# Add reverse relationship\nUser.orders = RelatedSet(Order, \"user_id\")\n\n# Usage - transparent lazy loading\nuser = User(user_id=1, name=\"Alice\")\nuser.save()\n\norder = Order(order_id=101, user_id=1, amount=99.99)\norder.save()\n\n# Access related objects\norder = Order.get(order_id=101)\nprint(order.user.name)  # \"Alice\" - lazy loads User\n\nuser = User.get(user_id=1)\nfor order in user.orders:\n    print(f\"Order {order.order_id}: ${order.amount}\")\n```\n\n### Many-to-Many Relationships\n\n```python\n@dataclass\nclass Student(Document):\n    class Meta:\n        collection_name = \"students\"\n        indexed_fields = [\"student_id\"]\n\n    student_id: int\n    name: str\n\n@dataclass\nclass Course(Document):\n    class Meta:\n        collection_name = \"courses\"\n        indexed_fields = [\"course_id\"]\n\n    course_id: int\n    title: str\n\n# Define bidirectional many-to-many\nStudent.courses = ManyToMany(\n    Course,\n    through=\"enrollments\",\n    local_field=\"student_id\",\n    remote_field=\"course_id\"\n)\n\nCourse.students = ManyToMany(\n    Student,\n    through=\"enrollments\",\n    local_field=\"course_id\",\n    remote_field=\"student_id\"\n)\n\n# Usage\nstudent = Student(student_id=1, name=\"Alice\")\nstudent.save()\n\nmath = Course(course_id=101, title=\"Mathematics\")\nmath.save()\n\n# Create relationship\nstudent.courses.add(math)\n\n# Navigate both directions\nprint(f\"{student.name} is enrolled in {len(student.courses)} courses\")\nprint(f\"{math.title} has {len(math.students)} students\")\n```\n\n### Relationship Features\n\n- **ForeignKey** - Many-to-one relationships with lazy loading and caching\n- **RelatedSet** - One-to-many reverse relationships with query/filter methods\n- **ManyToMany** - Many-to-many relationships through automatic junction tables\n- **Bidirectional Navigation** - Navigate relationships from both sides\n- **Transaction Support** - All relationship operations are transaction-aware\n- **Type Safety** - Full generic type hints for IDE autocomplete\n\nSee [docs/relationships.md](docs/relationships.md) for complete documentation and `examples/relationships_example.py` for 26 detailed examples.\n\n## When to Use KenobiX\n\n### Perfect For:\n- ✅ Applications with 1,000 - 1,000,000+ documents\n- ✅ Frequent searches and updates\n- ✅ Known query patterns (can index those fields)\n- ✅ Complex document structures\n- ✅ Need sub-millisecond query times\n- ✅ Prototypes that need to scale\n\n### Consider Alternatives For:\n- ⚠️ Pure insert-only workloads (indexing overhead not worth it)\n- ⚠️ \u003c 100 documents (overhead not justified)\n- ⚠️ Truly massive scale (\u003e 10M documents - use PostgreSQL/MongoDB)\n\n## When to Use Transactions\n\n### Use Transactions For:\n- ✅ **Financial operations** - Balance transfers, payments, refunds\n- ✅ **Multi-step updates** - Ensuring related data stays consistent\n- ✅ **Batch operations** - 50-100x performance boost for bulk inserts\n- ✅ **Business logic invariants** - Total inventory, account balances, quotas\n- ✅ **Error recovery** - Automatic rollback on exceptions\n\n### Auto-commit is Fine For:\n- ⚠️ Single document inserts/updates (no performance benefit)\n- ⚠️ Independent operations (no consistency requirements)\n- ⚠️ Read-only queries (no transaction needed)\n\n**Performance Note:** Transactions can improve bulk insert performance by 50-100x by deferring commit until the end.\n\n```python\n# Without transaction: ~2000ms for 1000 inserts\nfor doc in documents:\n    db.insert(doc)  # Commits after each insert\n\n# With transaction: ~20ms for 1000 inserts (100x faster)\nwith db.transaction():\n    for doc in documents:\n        db.insert(doc)  # Single commit at end\n```\n\n## Index Selection Strategy\n\n**Rule of thumb:** Index your 3-6 most frequently queried fields.\n\n```python\n# Good indexing strategy\ndb = KenobiX('app.db', indexed_fields=[\n    'user_id',      # Primary lookups\n    'email',        # Authentication\n    'status',       # Filtering\n    'created_at',   # Time-based queries\n])\n\n# Each index adds ~5-10% insert overhead\n# But provides 15-665x speedup on queries/updates\n```\n\n## API Documentation\n\n### Initialization\n\n```python\nKenobiX(file, indexed_fields=None)\n```\n\n- `file`: Path to SQLite database (created if doesn't exist)\n- `indexed_fields`: List of document fields to create indexes for\n\n### CRUD Operations\n\n```python\ndb.insert(document)                    # Insert single document\ndb.insert_many(documents)              # Bulk insert\ndb.search(key, value, limit=100)       # Search by field\ndb.search_optimized(**filters)         # Multi-field search\ndb.update(key, value, new_dict)        # Update matching documents\ndb.remove(key, value)                  # Remove matching documents\ndb.purge()                             # Delete all documents\ndb.all(limit=100, offset=0)            # Paginated retrieval\n```\n\n### Transaction Operations\n\n```python\n# Context manager (recommended)\nwith db.transaction():                 # Auto commit/rollback\n    db.insert(...)\n    db.update(...)\n\n# Manual control\ndb.begin()                             # Start transaction\ndb.commit()                            # Commit changes\ndb.rollback()                          # Discard changes\n\n# Savepoints (nested transactions)\nsp = db.savepoint()                    # Create savepoint\ndb.rollback_to(sp)                     # Rollback to savepoint\ndb.release_savepoint(sp)               # Release savepoint\n```\n\n### Advanced Operations\n\n```python\ndb.search_pattern(key, regex)          # Regex search (no index)\ndb.find_any(key, value_list)           # Match any value\ndb.find_all(key, value_list)           # Match all values\ndb.all_cursor(after_id, limit)         # Cursor pagination\ndb.explain(operation, *args)           # Query plan analysis\ndb.stats()                             # Database statistics\ndb.get_indexed_fields()                # List indexed fields\n```\n\n## Performance Tips\n\n1. **Index your query fields** - Biggest performance win (15-665x speedup)\n2. **Use transactions for bulk operations** - 50-100x faster for batch inserts\n3. **Use `search_optimized()` for multi-field queries** - More efficient than chaining\n4. **Use cursor pagination for large datasets** - Avoids O(n) OFFSET cost\n5. **Batch inserts with `insert_many()`** - Much faster than individual inserts\n6. **Check query plans with `explain()`** - Verify indexes are being used\n\n## Migration from KenobiDB\n\nKenobiX is API-compatible with KenobiDB. Simply:\n\n```python\n# Old\nfrom kenobi import KenobiDB\ndb = KenobiDB('app.db')\n\n# New (with performance boost)\nfrom kenobix import KenobiX\ndb = KenobiX('app.db', indexed_fields=['your', 'query', 'fields'])\n```\n\nExisting databases work without modification. Add `indexed_fields` to unlock performance gains.\n\n## Requirements\n\n- Python 3.11+\n- SQLite 3.31.0+ (for generated columns)\n\n## Testing\n\n```bash\n# Run all tests\npytest tests/\n\n# Run with coverage (90%+ coverage maintained)\npytest --cov=kenobix tests/\n\n# Run ACID compliance tests\npython3 tests/test_acid_compliance.py  # 25 comprehensive tests\npython3 tests/test_transactions.py     # 14 transaction tests\n\n# Run concurrency tests (uses multiprocessing)\npython3 tests/test_concurrency.py\n\n# Quick concurrency check\npython3 scripts/check_concurrency.py\n\n# Run benchmarks\npython benchmarks/benchmark_scale.py\npython benchmarks/benchmark_complexity.py\n```\n\n**Test Coverage:** KenobiX maintains 90%+ test coverage across:\n- Core database operations (kenobix.py: 88%+)\n- ODM layer (odm.py: 93%+)\n- 217 tests covering CRUD, indexing, concurrency, transactions, ODM, and relationships\n\n**ACID Compliance:** 25/25 comprehensive tests passing (100%):\n- 6 atomicity tests (all-or-nothing execution)\n- 5 consistency tests (data integrity invariants)\n- 5 isolation tests (concurrent transaction safety)\n- 7 durability tests (crash recovery simulation)\n- 2 combined tests (real-world scenarios)\n\n**Concurrency Tests:** Comprehensive multiprocessing tests verify:\n- Multiple readers run in parallel without blocking\n- Writers properly serialize via write lock\n- Readers not blocked by writers (WAL mode benefit)\n- Data integrity under concurrent access\n- Race condition detection\n\nSee [Concurrency Tests](docs/dev/concurrency-tests.md) for details.\n\n## Benchmarking\n\nComprehensive benchmarks included:\n\n```bash\n# Scale performance (1k-100k documents)\npython benchmarks/benchmark_scale.py --sizes \"1000,10000,100000\"\n\n# Document complexity impact\npython benchmarks/benchmark_complexity.py\n\n# ODM vs Raw performance comparison\npython benchmarks/benchmark_odm.py --size 10000\n```\n\n### ODM Performance\n\nThe ODM layer adds overhead for deserialization (cattrs). Results based on robust benchmarks (5 iterations, trimmed mean):\n\n- **Write operations**: ~7-15% slower (very acceptable)\n- **Read operations**: ~100-900% slower (cattrs deserialization cost)\n- **Count operations**: ~17% slower (minimal deserialization)\n- **Trade-off**: Type safety + developer productivity vs 2-10x slower reads\n\n**Key insight:** Write overhead is minimal. Read overhead is significant due to cattrs deserialization, not SQL queries (both use identical indexes).\n\nFor read-heavy workloads requiring maximum performance, use raw operations. For applications needing type safety and developer productivity, the ODM overhead is acceptable. You can also use a hybrid approach: ODM for most code, raw for hot paths.\n\n## Credits\n\n**KenobiX** is based on **[KenobiDB](https://github.com/patx/kenobi)** by **Harrison Erd**.\n\nThe original KenobiDB provided an excellent foundation with its MongoDB-like API and clean SQLite3 integration. KenobiX builds on this work by adding:\n\n- Full ACID transaction support with context manager API\n- Generated column indexes for 15-665x performance improvements\n- Optimized concurrency model (no RLock for reads)\n- Optional ODM layer with dataclass support\n- Cursor-based pagination\n- Query plan analysis tools\n- Comprehensive benchmark and test suites\n\nThank you to Harrison Erd for creating KenobiDB!\n\n## License\n\nBSD-3-Clause License (same as original KenobiDB)\n\nCopyright (c) 2025 KenobiX Contributors\n\nOriginal KenobiDB Copyright (c) Harrison Erd\n\nSee LICENSE file for details.\n\n## Contributing\n\nContributions welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch\n3. Add tests for new functionality\n4. Ensure all tests pass\n5. Submit a pull request\n\n## Links\n\n- **GitHub**: https://github.com/abilian/kenobix\n- **Original KenobiDB**: https://github.com/patx/kenobi\n- **PyPI**: https://pypi.org/project/kenobix/\n- **Benchmarks**: See `benchmarks/` directory\n\n## Changelog\n\nSee [CHANGES.md](CHANGES.md) for the complete changelog.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabilian%2Fkenobix","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fabilian%2Fkenobix","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabilian%2Fkenobix/lists"}