Skip to content

Explicit database handle for sync database access #365

Description

@bjester

Overview

This task (milestone M2) adds SyncDatabase, a handle that names the database that sync code uses. It also adds a test guard that fails when code queries the default database by mistake.

Background & Motivation

Sync code reaches the database in two implicit ways. ORM calls go through the host DATABASE_ROUTERS. Raw SQL and transactions always use "default". The archive is a second database, so archive code must name its database in every call.

The SQL backend also depends on the database. Today one backend object is chosen from the default connection. If the host uses PostgreSQL, the archive still uses SQLite, so each database needs its own backend.

Design: spec. Plan: implementation plan, Task 4.

Description & Expected Outcomes

SyncDatabase has two forms:

  • The routed default handle. It reproduces today's behavior exactly: ORM calls go through the routers, and raw SQL and transactions use "default".
  • A pinned handle for an explicit alias. All calls, ORM and raw SQL, go to that alias.

The handle gives a model manager, a connection, a SQL backend, transactions, a cursor, and the current instance with an incremented counter. The module-level begin_transaction keeps its behavior.

The test guard is a context manager. It fails with the SQL text when a query reaches the default database inside it.

Deliverables & Contracts

The task delivers:

  • SyncDatabase in morango/sync/db.py, with the members that spec §3.3 lists.
  • assert_no_default_db_queries() in tests/testapp/tests/helpers.py.
  • The module-level begin_transaction and DBBackend names, with today's behavior.

Acceptance Criteria

  • SyncDatabase.default().manager(Store) is Store._default_manager.
  • A handle pinned to default2 returns a manager that uses default2.
  • The backend of a SQLite alias is the SQLite wrapper.
  • A transaction on a pinned handle opens on that alias only.
  • current_instance_and_increment_counter() on the default handle increments the current instance counter by 1.
  • The guard fails on a query to default and passes on a query to default2.
  • The characterization suite passes without edits.

Technical Pointers & Architecture

  • Target Components: morango/sync/db.py:15-37 (begin_transaction), morango/sync/backends/utils.py (load_backend), morango/models/core.py:191 (get_current_instance_and_increment_counter).
  • Related Patterns: tests/testapp/testapp/db.py (TestingRouter) is a router that sends ORM calls to another database. The routed default handle must keep that behavior.
  • Data Model & Schema Considerations: None.
  • Resilience & Failure Modes: The handle adds no fallback. A wrong alias fails with the Django error.

Notes & Tradeoffs

Metadata

  • Complexity: Medium
  • Target Branch: release-v0.9.x

AI Usage

Drafted with Claude (Claude Code) from the approved design spec and implementation plan. The author reviewed the requirements, and the code references were checked against the release-v0.9.x codebase.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions