1 Commits

Author SHA1 Message Date
300e1bf7b4 Phase 16: async API (informix_db.aio)
Ships AsyncConnection, AsyncCursor, and AsyncConnectionPool that
expose async/await versions of the sync API for use with FastAPI,
aiohttp, etc.

Strategy: thread-pool wrapping (aiopg pattern), not native async.
Each blocking I/O call is offloaded to a worker thread via
asyncio.to_thread. The event loop never blocks; queries run in
parallel up to the pool's max_size. Cost: ~250 lines, no changes
to the sync codebase. Native async (Phase 17) would require a
~2000-line transport abstraction refactor — deferred until a real
workload needs it.

For typical FastAPI/aiohttp workloads (request → one query → return),
this is functionally equivalent to native async. Each await yields
the loop while a worker thread does the I/O. Only differs for
hundreds-of-concurrent-connections workloads.

API mirrors the sync API one-to-one:

  import asyncio
  from informix_db import aio

  async def main():
      pool = await aio.create_pool(host=..., min_size=1, max_size=10)
      async with pool.connection() as conn:
          cur = await conn.cursor()
          await cur.execute("SELECT id FROM users WHERE name = ?", (name,))
          row = await cur.fetchone()
      await pool.close()

The async pool preserves the sync pool's eviction policy: connection
errors evict, application errors retain.

Tests: 9 integration tests in test_aio.py covering open/close,
async-with, simple/parameterized SELECT, async-for cursor iteration,
pool acquire/release, 20-query concurrent gather (verifies parallelism
through max_size=5 pool), pool async context manager, commit/rollback.

Total: 69 unit + 163 integration = 232 tests.

Pyproject changes:
* Added pytest-asyncio>=1.3.0 as dev dep
* asyncio_mode = "auto" so async tests don't need decorators

Architectural completion: with Phase 16, every backlog item is
done. The Phase 0 ambition — first pure-Python Informix driver,
no native deps — is now genuinely complete.
2026-05-04 14:58:19 -06:00