Database

class dsviper.Database

Bases: object

A Database is a CRUD like transactional database. Use the static factory method create_in_memory(), create(…), open(…), connect(…) or connect_local(…).

Transactional is a precondition, not a feature: reads need no transaction, and every WRITE requires one already open - set, delete and the blob operations raise without writing anything when there is none. extend_definitions is the exception in both directions, opening an exclusive transaction of its own. A CommitDatabase does NOT work this way: its writes need no transaction at all.

One file may be open in several processes; SQLite locks it. While a transaction writes, another writer waits, and in ‘Exclusive’ mode a reader waits too - for up to 10 seconds, after which the call raises ViperError: the database is busy. Otherwise a reader sees the last committed state.

Note: Not directly instantiable.

attachment_getting() → AttachmentGetting

Return the AttachmentGetting interface.

begin_transaction(mode: str | None = None) → None

Begin a transaction in mode ‘Deferred’ (the default), ‘Immediate’ or ‘Exclusive’.

Another spelling raises.

Transactions do not nest: calling this while in_transaction() is True raises, and the transaction already open is untouched.

blob(blob_id: ValueBlobId) → ValueBlob | None

Return the bytes of the blob blob_id names, or None if it is not held here.

Raises past 2 GB, where the bytes cannot be handed over in one piece. Ask blob_info(blob_id).chunked() first, and read such a blob with read_blob.

A blob databasing().create_zero_blob reserved raises until databasing().freeze_blob seals it; blob_info answers None for it meanwhile.

blob_getting() → BlobGetting

Return the BlobGetting interface.

blob_ids() → set[ValueBlobId]

Return the set of blob_id of every sealed blob.

A blob databasing().create_zero_blob reserved joins it once databasing().freeze_blob seals it.

blob_info(blob_id: ValueBlobId) → BlobInfo | None

Return the BlobInfo for blob_id, or None if the database does not hold it.

It gives the layout, the size and whether the blob is chunked. A blob databasing().create_zero_blob reserved answers None until databasing().freeze_blob seals it.

blob_infos(blob_ids: set[ValueBlobId]) → list[BlobInfo]

Return one BlobInfo per blob_id of blob_ids the database holds.

An unknown blob_id is left out, so the list may be shorter than blob_ids.

blob_statistics() → BlobStatistics

Return the statistics for blobs.

blob_stream_append(blob_stream: BlobStream, blob: ValueBlob) → None

Append blob to blob_stream, after the bytes already written.

Requires an open transaction, and raises without writing when there is none.

A failure here closes the stream and discards what it collected, so nothing partial is left behind and there is nothing to clean up.

blob_stream_close(blob_stream: BlobStream) → ValueBlobId

Close blob_stream and return its blob_id.

The blob_id is computed from everything written into it. Requires an open transaction, and raises without writing when there is none.

A failure here closes the stream and discards what it collected, so nothing partial is left behind and there is nothing to clean up.

blob_stream_create(blob_layout: BlobLayout, size: int) → BlobStream

Return a BlobStream to fill a blob of size bytes laid out by blob_layout.

Requires an open transaction, and raises without writing when there is none.

close() → None

Close the database.

codec_name() → str

Return the name of the codec.

commit()

Commit the transaction, so what it wrote stays.

Raises when no transaction is open.

static connect(database: str, host: str, service: str = '54322') → Database

Return the database named database, served by host on service.

static connect_local(database: str, socket_path: str) → Database

Return the database named database, served on the unix socket socket_path.

static create(file_path: str, *, documentation: str | None = None) → Database

Create a database at file_path and return it.

documentation is stored in the file and read back by documentation().

Requires that nothing exist at file_path, and raises without creating anything when something does.

create_blob(blob_layout: BlobLayout, blob: ValueBlob) → ValueBlobId

Store blob under blob_layout.

Returns the blob_id computed from its content and that layout. Requires an open transaction, and raises without writing when there is none.

create_blob_from_buffer(buffer) → ValueBlobId

Store the bytes of a buffer or a ValueBlob; return their blob_id.

Requires an open transaction, and raises without writing when there is none.

static create_in_memory() → Database

Create and return a database in memory.

static databases(host: str, service: str = '54322') → list[str]

Return the names of the databases host serves on service.

static databases_local(socket_path: str) → list[str]

Return the names of the databases served on the unix socket socket_path.

databasing() → Databasing

Return the Databasing interface.

definitions() → DefinitionsConst

Return the Definitions every value in the database is typed by.

It is a SNAPSHOT: extending the database afterwards does not show through the handle you hold, so ask again. A view obtained from Definitions.const() is live instead - same class, opposite liveness.

definitions_hexdigest() → str

Return the SHA1 of the definitions, as a hex string.

del_blob(blob_id: ValueBlobId) → bool

Delete the blob blob_id names, and return True if it was there.

Requires an open transaction, and raises without writing when there is none.

delete(attachment: Attachment, key: ValueKey) → bool

Delete the document attachment holds at key.

Returns True if it was there. Requires an open transaction, and raises without writing when there is none.

documentation() → str

Return the free text stored with the database at create(). One made without any answers ‘not documented.’, one made in memory answers ‘In Memory’ - both are placeholders written in at create(), not substituted on read.

extend_definitions(definitions: DefinitionsConst) → DefinitionsExtendInfo

Add every type and attachment of definitions the database lacks.

It opens an exclusive transaction of its own, so it raises when one is already open - the reverse of every other write here.

get(attachment: Attachment, key: ValueKey) → ValueOptional

Return a ValueOptional over the document attachment holds at key.

Always a ValueOptional, never None: ask is_nil() whether it holds anything, and unwrap() for the document itself.

An absent document answers a nil ValueOptional; a key of another concept than the one attachment files raises, so is_nil() reports absence and never a mismatched key.

The document comes back as a copy; mutating it does not reach what is stored.

has(attachment: Attachment, key: ValueKey) → bool

Return True if attachment holds a document at key.

in_memory() → bool

Return True if the database is in memory.

in_transaction() → bool

Return True if a transaction is running.

is_closed() → bool

Return True if the database is closed.

static is_compatible(file_path: str) → bool

Return True if the file at file_path carries the expected SQL schema.

keys(attachment: Attachment) → ValueSet

Return every key attachment holds a document for.

The set is taken now: a later write does not reach it.

static open(file_path: str, readonly: bool = False) → Database

Open the database at file_path and return it.

readonly opens it without allowing a write.

Requires a file at file_path, and raises when there is none.

path() → str

Return the file path the database was opened from.

A database made in memory answers ‘InMemory’ rather than a path, and that exact string is how the runtime recognises one, so no file may take it: creating or opening a file of that path raises. Over a socket the answer is whatever the server answers for its own database.

read_blob(blob_id: ValueBlobId, size: int, offset: int) → ValueBlob

Return size bytes of the blob blob_id names, starting at offset.

The read side of blob_stream_create, blob_stream_append and blob_stream_close, and the only way to read a blob past 2 GB, which blob() refuses.

rollback()

Roll back the transaction, so what it wrote is dropped.

Raises when no transaction is open.

set(attachment: Attachment, key: ValueKey, value: _InputValues) → bool

Write value into attachment at key, replacing what was there.

The value is copied in: mutating it afterwards does not reach what was written, and writing the same object under two keys stores two independent documents.

Returns True when the document was written; a check that refuses raises instead of answering. It needs an attachment extend_definitions has registered - an unregistered one raises whatever the transaction - and an open transaction, without which it raises and writes nothing.

uuid() → ValueUUId

Return the uuid identifying this database, generated at create().