# Reading and inserting data
The format for writing data is the same in both Set and VerifiedSet, as is the same for reading data in both Get and VerifiedGet.
The only difference is that VerifiedSet returns proofs needed to mathematically verify that the data was not tampered. Note that generating that proof has a slight performance impact, so primitives are allowed without the proof. It is still possible get the proofs for a specific item at any time, so the decision about when or how frequently to do checks (with the Verify version of a method) is completely up to the user. It's possible also to use dedicated auditors to ensure the database consistency, but the pattern in which every client is also an auditor is the more interesting one.
# Get and Set
# Get at and since a transaction
You can retrieve a key on a specific transaction with VerifiedGetAt and since a specific transaction with VerifiedGetSince.
# Retrieving transactions by ID
It's possible to retrieve all the keys inside a specific transaction.
# Retrieving verified transactions by ID
It's possible to retrieve all the keys inside a specific verified transaction.
# Retrieving transactions by ID with filters
The transaction entries are generated by writing key-value pairs, referencing keys, associating scores to key-value pairs (with ZAdd operation), and by mapping SQL data model into key-value model.
With TxByIDWithSpec operation it's possible to retrieve entries of certain types, either retrieving the digest of the value assigned to the key (EntryTypeAction_ONLY_DIGEST), the raw value (EntryTypeAction_RAW_VALUE) or the structured value (EntryTypeAction_RESOLVE).
# Conditional writes
Immudb can check additional preconditions before the write operation is made. Precondition is checked atomically with the write operation. It can be then used to ensure consistent state of data inside the database.
Following preconditions are supported:
- MustExist - precondition checks if given key exists in the database, this precondition takes into consideration logical deletion and data expiration, if the entry was logically deleted or has expired, MustExist precondition for such entry will fail
- MustNotExist - precondition checks if given key does not exist in the database, this precondition also takes into consideration logical deletion and data expiration, if the entry was logically deleted or has expired, MustNotExist precondition for such entry will succeed
- NotModifiedAfterTX - precondition checks if given key was not modified after given transaction id, local deletion and setting entry with expiration data is also considered modification of the entry
In many cases, keys used for constraints will be the same as keys for written entries. A good example here is a situation when a value is set only if that key does not exist. This is not strictly required - keys used in constraints do not have to be the same or even overlap with keys for modified entries. An example would be if only one of two keys should exist in the database. In such case, the first key will be modified and the second key will be used for MustNotExist constraint.
A write operation using precondition can not be done in an asynchronous way. Preconditions are checked twice when processing such requests - first check is done against the current state of internal index, the second check is done just before persisting the write and requires up-to-date index.
Preconditions are available on SetAll, Reference and ExecAll operations.