co3.database module

Database

Central object for defining storage protocol-specific interfaces. The database wraps up central items for interacting with database resources, namely the Accessor and Manager objects.

The Database type hierarchy attempts to be exceedingly general; SQL-derivatives should subclass from the RelationalDatabase subtype, for example, which itself becomes a new generic via a type dependence on Relation.

While relying no many constituent pieces, Databases intend to provide all needed objects under one roof. This includes the Engine (opens up connections to the database), Accessors (running select-like queries on DB data), Managers (updating DB state with sync insert-like actions), and Indexers (systematically caching Accessor queries). Generalized behavior is supported by explicitly leveraging the individual components. For example,

with db.engine.connect() as connection:
    db.access.select(
        connection,
        <query>
    )
    db.manager.insert(
        connection,
        component,
        data
    )

The Database also supports a few directly callable methods for simplified interaction. These methods manage a connection context internally, passing them through the way they might otherwise be handled explicitly, as seen above.

db.select(<query>)

db.insert(<query>, data)

on explicit connection contexts

Older models supported Accessors/Managers that housed their own Engine instances, and when performing actions like insert, the Engine would be passed all the way through until a Connection could be spawned, and in that context the single action would be made. This model forfeits a lot of connection control, preventing multiple actions under a single connection.

The newer model now avoids directly allowing Managers/Accessors access to their own engines, and instead they expose methods that explicitly require Connection objects. This means a user can invoke these methods in their own Connection contexts (seen above) and group up operations as they please, reducing overhead. The Database then wraps up a few single-operation contexts where outer connection control is not needed.

class co3.database.Database(*engine_args, **engine_kwargs)[source]

Bases: Generic

Generic Database definition

Generic to both a Component (C), and an Engine resource type (R). The Engine’s generic openness must be propagated here, as it’s intended to be fully abstracted away under the Database roof. Note that we cannot explicitly use an Engine type in its place, as it obscures its internal resource type dependence when we need it for hinting here in __init__.

Development TODO list

Decide on official ruling for assigning Schema objects, and verifying any attempted Component-based actions (e.g., inserts, selects) to belong to or be a composition of Components within an attached Schema. Reasons for: helps complete the sense of a “Database” here programmatically, incorporating a more structurally accurate representation of allowed operations, and prevent possible attribute and type collisions. Reasons against: generally not a huge concern to align Schemas as transactions will rollback, broadly increases a bit of bulk, and users often expected know which components belong to a particular DB. Leaning more to for, and would only apply to the directly supported method passthroughs (and thus would have no impact on independent methods like Accessor.raw_select). Additionally, even if component clashes don’t pose serious risk, it can be helpful to systematically address the cases where a misalignment is occurring (by having helpful verify methods that can be ran before any actions).

__init__(*engine_args, **engine_kwargs)[source]
Parameters:
  • engine_args – positional arguments to pass on to the Engine object during instantiation

  • engine_kwargs – keyword arguments to pass on to the Engine object during instantiation

Variables:
_local_cache: a database-local property store for ad-hoc CacheBlock-esque

methods, that are nevertheless _not_ query/group-by responses to pass on to the Indexer. Dependent properties should write to the this cache and check for existence of stored results; the cache state must be managed globally.

property index
insert(component, *args, **kwargs)[source]
property manage

Accessing .manage queues a cache clear on the external index, as well wipes the local index.

populate_indexes()[source]
raw_query(connection, query)[source]
recreate(schema)[source]
select(component, *args, **kwargs)[source]

Dev note

args and kwargs have to be general/unspecified here due to the possible passthrough method adopting arbitrary parameters in subtypes. I could simply overload this method in the relevant inheriting DBs (i.e., by matching the expected Accessor’s .select signature).