Repository: codenotary/immudb-py (language: python)

Issue:
Support for VerifiedGetSince method
Currently there is no option to get verified data since some transaction, and immudb already supports it 


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9b237ed..2edd425 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -21,7 +21,7 @@ jobs:
           make dev
       - name: Start immudb container
         run: |
-          docker run -d --health-cmd "immuadmin status" --health-interval 10s --health-timeout 5s --health-retries 5 -v ${{ github.workspace }}/tests/certs/my.key.pem:/key.pem -p 3322:3322 codenotary/immudb:1.2.2 --signingKey=/key.pem
+          docker run -d --health-cmd "immuadmin status" --health-interval 10s --health-timeout 5s --health-retries 5 -v ${{ github.workspace }}/tests/certs/my.key.pem:/key.pem -p 3322:3322 codenotary/immudb:1.2.3 --signingKey=/key.pem
           docker run -d --health-cmd "immuadmin status" --health-interval 10s --health-timeout 5s --health-retries 5 -v ${{ github.workspace }}/tests/certs/my.key.pem:/key.pem -p 3333:3322 codenotary/immudb:1.1.0 --signingKey=/key.pem
       - name: Run tests
         run: |
diff --git a/Makefile b/Makefile
index a8178e8..9ae4ad5 100644
--- a/Makefile
+++ b/Makefile
@@ -27,6 +27,9 @@ test:
 coverage:
 	$(COVERAGE) run -m pytest tests
 
+coverage-report:
+	$(COVERAGE) html
+
 install:
 	$(PYTHON) setup.py install
 
diff --git a/immudb/client.py b/immudb/client.py
index 0ccf3ad..febdea7 100644
--- a/immudb/client.py
+++ b/immudb/client.py
@@ -15,7 +15,7 @@
 
 from immudb import header_manipulator_client_interceptor
 from immudb.handler import (batchGet, batchSet, changePassword, changePermission, createUser,
-                            currentRoot, createDatabase, databaseList, useDatabase,
+                            currentRoot, createDatabase, databaseList, deleteKeys, useDatabase,
                             get, listUsers, sqldescribe, verifiedGet, verifiedSet, setValue, history,
                             scan, reference, verifiedreference, zadd, verifiedzadd,
                             zscan, healthcheck, health, txbyid, verifiedtxbyid, sqlexec, sqlquery,
@@ -24,6 +24,10 @@
 from immudb.grpc import schema_pb2_grpc
 import warnings
 import ecdsa
+from immudb.datatypes import DeleteKeysRequest
+from immudb.embedded.store import KVMetadata
+
+import datetime
 
 
 class ImmudbClient:
@@ -47,29 +51,6 @@ def loadKey(self, kfile: str):
             with open(kfile) as f:
                 self.__vk = ecdsa.VerifyingKey.from_pem(f.read())
 
-    def login(self, username, password, database=b"defaultdb"):
-        req = schema_pb2_grpc.schema__pb2.LoginRequest(user=bytes(
-            username, encoding='utf-8'), password=bytes(
-                password, encoding='utf-8'
-        ))
-        try:
-            self.__login_response = schema_pb2_grpc.schema__pb2.LoginResponse = \
-                self.__stub.Login(
-                    req
-                )
-        except ValueError as e:
-            raise Exception(
-                "Attempted to login on termninated client, channel has been shutdown") from e
-
-        self.__stub = self.set_token_header_interceptor(self.__login_response)
-        # Select database, modifying stub function accordingly
-        request = schema_pb2_grpc.schema__pb2.Database(databaseName=database)
-        resp = self.__stub.UseDatabase(request)
-        self.__stub = self.set_token_header_interceptor(resp)
-
-        self.__rs.init("{}/{}".format(self.__url, database), self.__stub)
-        return self.__login_response
-
     def shutdown(self):
         self.channel.close()
         self.channel = None
@@ -98,57 +79,57 @@ def set_token_header_interceptor(self, response):
     def stub(self):
         return self.__stub
 
+# from here on same order as in Golang ImmuClient interface (pkg/client/client.go)
+
+    # Not implemented: disconnect
+    # Not implemented: isConnected
+    # Not implemented: waitForHealthCheck
     def healthCheck(self):
         return healthcheck.call(self.__stub, self.__rs)
 
-    def health(self):
-        return health.call(self.__stub, self.__rs)
-
-    def get(self, key: bytes):
-        return get.call(self.__stub, self.__rs, key)
-
-    def getValue(self, key: bytes):
-        ret = get.call(self.__stub, self.__rs, key)
-        if ret is None:
-            return None
-        return ret.value
-
-    def set(self, key: bytes, value: bytes):
-        return setValue.call(self.__stub, self.__rs, key, value)
-
-    def safeGet(self, key: bytes):
-        warnings.warn("Call to deprecated safeGet. Use verifiedGet instead",
-                      category=DeprecationWarning,
-                      stacklevel=2
-                      )
-        return verifiedGet.call(self.__stub, self.__rs, key, verifying_key=self.__vk)
+    # Not implemented: connect
 
-    def verifiedGet(self, key: bytes):
-        return verifiedGet.call(self.__stub, self.__rs, key, verifying_key=self.__vk)
+    def login(self, username, password, database=b"defaultdb"):
+        req = schema_pb2_grpc.schema__pb2.LoginRequest(user=bytes(
+            username, encoding='utf-8'), password=bytes(
+                password, encoding='utf-8'
+        ))
+        try:
+            self.__login_response = schema_pb2_grpc.schema__pb2.LoginResponse = \
+                self.__stub.Login(
+                    req
+                )
+        except ValueError as e:
+            raise Exception(
+                "Attempted to login on termninated client, channel has been shutdown") from e
 
-    def verifiedGetAt(self, key: bytes, atTx: int):
-        return verifiedGet.call(self.__stub, self.__rs, key, atTx, self.__vk)
+        self.__stub = self.set_token_header_interceptor(self.__login_response)
+        # Select database, modifying stub function accordingly
+        request = schema_pb2_grpc.schema__pb2.Database(databaseName=database)
+        resp = self.__stub.UseDatabase(request)
+        self.__stub = self.set_token_header_interceptor(resp)
 
-    def safeSet(self, key: bytes, value: bytes):
-        warnings.warn("Call to deprecated safeSet. Use verifiedSet instead",
-                      category=DeprecationWarning,
-                      stacklevel=2
-                      )
-        return verifiedSet.call(self.__stub, self.__rs, key, value)
+        self.__rs.init("{}/{}".format(self.__url, database), self.__stub)
+        return self.__login_response
 
-    def verifiedSet(self, key: bytes, value: bytes):
-        return verifiedSet.call(self.__stub, self.__rs, key, value, self.__vk)
+    def logout(self):
+        self.__stub.Logout(google_dot_protobuf_dot_empty__pb2.Empty())
+        self.__login_response = None
 
-    def getAllValues(self, keys: list):
-        resp = batchGet.call(self.__stub, self.__rs, keys)
-        return resp
+    # Not implemented: openSession
+    # Not implemented: closeSession
 
-    def getAll(self, keys: list):
-        resp = batchGet.call(self.__stub, self.__rs, keys)
-        return {key: value.value for key, value in resp.items()}
+    def createUser(self, user, password, permission, database):
+        request = schema_pb2_grpc.schema__pb2.CreateUserRequest(
+            user=bytes(user, encoding='utf-8'),
+            password=bytes(password, encoding='utf-8'),
+            permission=permission,
+            database=database
+        )
+        return createUser.call(self.__stub, self.__rs, request)
 
-    def setAll(self, kv: dict):
-        return batchSet.call(self.__stub, self.__rs, kv)
+    def listUsers(self):
+        return listUsers.call(self.__stub, None)
 
     def changePassword(self, user, newPassword, oldPassword):
         request = schema_pb2_grpc.schema__pb2.ChangePasswordRequest(
@@ -161,28 +142,29 @@ def changePassword(self, user, newPassword, oldPassword):
     def changePermission(self, action, user, database, permissions):
         return changePermission.call(self.__stub, self.__rs, action, user, database, permissions)
 
-    def createUser(self, user, password, permission, database):
-        request = schema_pb2_grpc.schema__pb2.CreateUserRequest(
-            user=bytes(user, encoding='utf-8'),
-            password=bytes(password, encoding='utf-8'),
-            permission=permission,
-            database=database
-        )
-        return createUser.call(self.__stub, self.__rs, request)
+    # Not implemented: updateAuthConfig
+    # Not implemented: updateMTLSConfig
 
-    def listUsers(self):
-        return listUsers.call(self.__stub, None)
+    # Not implemented: with[.*]
+
+    # Not implemented: getServiceClient
+    # Not implemented: getOptions
+    # Not implemented: setupDialOptions
 
     def databaseList(self):
         dbs = databaseList.call(self.__stub, self.__rs, None)
         return [x.databaseName for x in dbs.dblist.databases]
 
-    def databaseUse(self, dbName: bytes):
-        warnings.warn("Call to deprecated databaseUse. Use useDatabase instead",
-                      category=DeprecationWarning,
-                      stacklevel=2
-                      )
-        return self.useDatabase(dbName)
+    # Not implemented: databaseListV2
+
+    def createDatabase(self, dbName: bytes):
+        request = schema_pb2_grpc.schema__pb2.Database(databaseName=dbName)
+        return createDatabase.call(self.__stub, self.__rs, request)
+
+    # Not implemented: createDatabaseV2
+    # Not implemented: loadDatabase
+    # Not implemented: unloadDatabase
+    # Not implemented: deleteDatabase
 
     def useDatabase(self, dbName: bytes):
         request = schema_pb2_grpc.schema__pb2.Database(databaseName=dbName)
@@ -192,35 +174,52 @@ def useDatabase(self, dbName: bytes):
         self.__rs.init(dbName, self.__stub)
         return resp
 
-    def createDatabase(self, dbName: bytes):
-        request = schema_pb2_grpc.schema__pb2.Database(databaseName=dbName)
-        return createDatabase.call(self.__stub, self.__rs, request)
+    # Not implemented: updateDatabase
+    # Not implemented: updateDatabaseV2
+    # Not implemented: getDatabaseSettings
+    # Not implemented: getDatabaseSettingsV2
 
-    def databaseCreate(self, dbName: bytes):
-        warnings.warn("Call to deprecated databaseCreate. Use createDatabase instead",
-                      category=DeprecationWarning,
-                      stacklevel=2
-                      )
-        return self.createDatabase(dbName)
+    # Not implemented: setActiveUser
+
+    # Not implemented: flushIndex
+
+    def compactIndex(self):
+        self.__stub.CompactIndex(google_dot_protobuf_dot_empty__pb2.Empty())
+
+    def health(self):
+        return health.call(self.__stub, self.__rs)
 
     def currentState(self):
         return currentRoot.call(self.__stub, self.__rs, None)
 
-    def history(self, key: bytes, offset: int, limit: int, sortorder: bool):
-        return history.call(self.__stub, self.__rs, key, offset, limit, sortorder)
+    def set(self, key: bytes, value: bytes):
+        return setValue.call(self.__stub, self.__rs, key, value)
 
-    def logout(self):
-        self.__stub.Logout(google_dot_protobuf_dot_empty__pb2.Empty())
-        self.__login_response = None
+    def verifiedSet(self, key: bytes, value: bytes):
+        return verifiedSet.call(self.__stub, self.__rs, key, value, self.__vk)
 
-    def scan(self, key: bytes, prefix: bytes, desc: bool, limit: int, sinceTx: int = None):
-        return scan.call(self.__stub, self.__rs, key, prefix, desc, limit, sinceTx)
+    def expireableSet(self, key: bytes, value: bytes, expiresAt: datetime.datetime):
+        metadata = KVMetadata()
+        metadata.ExpiresAt(expiresAt)
+        return setValue.call(self.__stub, self.__rs, key, value, metadata)
 
-    def setReference(self, referredkey: bytes, newkey:  bytes):
-        return reference.call(self.__stub, self.__rs, referredkey, newkey)
+    def get(self, key: bytes):
+        return get.call(self.__stub, self.__rs, key)
 
-    def verifiedSetReference(self, referredkey: bytes, newkey:  bytes):
-        return verifiedreference.call(self.__stub, self.__rs, referredkey, newkey, verifying_key=self.__vk)
+    # Not implemented: getSince
+    # Not implemented: getAt
+
+    def verifiedGet(self, key: bytes):
+        return verifiedGet.call(self.__stub, self.__rs, key, verifying_key=self.__vk)
+
+    def verifiedGetSince(self, key: bytes, sinceTx: int):
+        return verifiedGet.call(self.__stub, self.__rs, key, sinceTx, self.__vk)
+
+    def verifiedGetAt(self, key: bytes, atTx: int):
+        return verifiedGet.call(self.__stub, self.__rs, key, atTx, self.__vk)
+
+    def history(self, key: bytes, offset: int, limit: int, sortorder: bool):
+        return history.call(self.__stub, self.__rs, key, offset, limit, sortorder)
 
     def zAdd(self, zset: bytes, score: float, key: bytes, atTx: int = 0):
         return zadd.call(self.__stub, self.__rs, zset, score, key, atTx)
@@ -228,6 +227,12 @@ def zAdd(self, zset: bytes, score: float, key: bytes, atTx: int = 0):
     def verifiedZAdd(self, zset: bytes, score: float, key: bytes, atTx: int = 0):
         return verifiedzadd.call(self.__stub, self.__rs, zset, score, key, atTx, self.__vk)
 
+    # Not implemented: zAddAt
+    # Not implemented: verifiedZAddAt
+
+    def scan(self, key: bytes, prefix: bytes, desc: bool, limit: int, sinceTx: int = None):
+        return scan.call(self.__stub, self.__rs, key, prefix, desc, limit, sinceTx)
+
     def zScan(self, zset: bytes, seekKey: bytes, seekScore: float,
               seekAtTx: int, inclusive: bool, limit: int, desc: bool, minscore: float,
               maxscore: float, sinceTx=None, nowait=False):
@@ -241,6 +246,42 @@ def txById(self, tx: int):
     def verifiedTxById(self, tx: int):
         return verifiedtxbyid.call(self.__stub, self.__rs, tx, self.__vk)
 
+    # Not implemented: txByIDWithSpec
+
+    # Not implemented: txScan
+
+    # Not implemented: count
+    # Not implemented: countAll
+
+    def setAll(self, kv: dict):
+        return batchSet.call(self.__stub, self.__rs, kv)
+
+    def getAll(self, keys: list):
+        resp = batchGet.call(self.__stub, self.__rs, keys)
+        return {key: value.value for key, value in resp.items()}
+
+    def delete(self, req: DeleteKeysRequest):
+        return deleteKeys.call(self.__stub, req)
+
+    def execAll(self, ops: list, noWait=False):
+        return execAll.call(self.__stub, self.__rs, ops, noWait)
+
+    def setReference(self, referredkey: bytes, newkey:  bytes):
+        return reference.call(self.__stub, self.__rs, referredkey, newkey)
+
+    def verifiedSetReference(self, referredkey: bytes, newkey:  bytes):
+        return verifiedreference.call(self.__stub, self.__rs, referredkey, newkey, verifying_key=self.__vk)
+
+    # Not implemented: setReferenceAt
+    # Not implemented: verifiedSetReferenceAt
+
+    # Not implemented: dump
+
+    # Not implemented: stream[.*]
+
+    # Not implemented: exportTx
+    # Not implemented: replicateTx
+
     def sqlExec(self, stmt, params={}, noWait=False):
         """Executes an SQL statement
         Args:
@@ -281,11 +322,51 @@ def listTables(self):
         """
         return listtables.call(self.__stub, self.__rs)
 
-    def execAll(self, ops: list, noWait=False):
-        return execAll.call(self.__stub, self.__rs, ops, noWait)
-
-    def compactIndex(self):
-        self.__stub.CompactIndex(google_dot_protobuf_dot_empty__pb2.Empty())
-
     def describeTable(self, table):
         return sqldescribe.call(self.__stub, self.__rs, table)
+
+    # Not implemented: verifyRow
+    # Not implemented: newTx
+
+# deprecated
+    def databaseCreate(self, dbName: bytes):
+        warnings.warn("Call to deprecated databaseCreate. Use createDatabase instead",
+                      category=DeprecationWarning,
+                      stacklevel=2
+                      )
+        return self.createDatabase(dbName)
+
+    def safeGet(self, key: bytes):  # deprecated
+        warnings.warn("Call to deprecated safeGet. Use verifiedGet instead",
+                      category=DeprecationWarning,
+                      stacklevel=2
+                      )
+        return verifiedGet.call(self.__stub, self.__rs, key, verifying_key=self.__vk)
+
+    def databaseUse(self, dbName: bytes):  # deprecated
+        warnings.warn("Call to deprecated databaseUse. Use useDatabase instead",
+                      category=DeprecationWarning,
+                      stacklevel=2
+                      )
+        return self.useDatabase(dbName)
+
+    def safeSet(self, key: bytes, value: bytes):  # deprecated
+        warnings.warn("Call to deprecated safeSet. Use verifiedSet instead",
+                      category=DeprecationWarning,
+                      stacklevel=2
+                      )
+        return verifiedSet.call(self.__stub, self.__rs, key, value)
+
+
+# immudb-py only
+
+
+    def getAllValues(self, keys: list):  # immudb-py only
+        resp = batchGet.call(self.__stub, self.__rs, keys)
+        return resp
+
+    def getValue(self, key: bytes):  # immudb-py only
+        ret = get.call(self.__stub, self.__rs, key)
+        if ret is None:
+            return None
+        return ret.value
diff --git a/immudb/datatypes.py b/immudb/datatypes.py
index 4b0dc04..7543f60 100644
--- a/immudb/datatypes.py
+++ b/immudb/datatypes.py
@@ -75,6 +75,7 @@ class ReferenceRequest():
     atTx: int
     boundRef: bool
     noWait: bool
+    # TODO: Preconditions
 
     def __init__(self, key, referencedKey, atTx=0, noWait=False):
         self.key = key
@@ -92,3 +93,15 @@ class ColumnDescription:
     index: str
     autoincrement: bool
     unique: bool
+
+
+@dataclass
+class DeleteKeysRequest():
+    keys: list
+    sinceTx: int
+    noWait: bool
+
+    def __init__(self, keys, sinceTx=0, noWait=False):
+        self.keys = keys
+        self.sinceTx = sinceTx
+        self.noWait = noWait
diff --git a/immudb/embedded/store/kv_metadata.py b/immudb/embedded/store/kv_metadata.py
index 5e2f8cf..5d3c2a1 100644
--- a/immudb/embedded/store/kv_metadata.py
+++ b/immudb/embedded/store/kv_metadata.py
@@ -17,6 +17,7 @@
 
 DELETED_ATTR_CODE = 0
 EXPIRES_AT_ATTR_CODE = 1
+NON_INDEXABLE_ATTR_CODE = 2
 
 
 class KVMetadata():
@@ -24,18 +25,6 @@ def __init__(self):
         self.attributes = dict()
         self.readonly = False
 
-    def Bytes(self):
-        b = b''
-        for attrCode in [DELETED_ATTR_CODE, EXPIRES_AT_ATTR_CODE]:
-            if attrCode in self.attributes:
-                b = b+attrCode.to_bytes(1, 'big')
-                if attrCode == EXPIRES_AT_ATTR_CODE:
-                    # The attribute is a datetime. Convert it to epoch integer big endian 64 bit
-                    b = b + \
-                        int(self.attributes[attrCode].replace(tzinfo=datetime.timezone.utc).timestamp()).to_bytes(
-                            8, 'big')
-        return b
-
     def AsDeleted(self, deleted: bool):
         if self.readonly:
             raise ErrReadOnly
@@ -63,3 +52,26 @@ def ExpirationTime(self) -> datetime.datetime:
             return self.attributes[EXPIRES_AT_ATTR_CODE]
         else:
             raise ErrNonExpirable
+
+    def AsNonIndexable(self, nonIndexable: bool):
+        if self.readonly:
+            raise ErrReadOnly
+        if not nonIndexable:
+            self.attributes.pop(NON_INDEXABLE_ATTR_CODE, None)
+        else:
+            self.attributes[NON_INDEXABLE_ATTR_CODE] = None
+
+    def NonIndexable(self) -> bool:
+        return NON_INDEXABLE_ATTR_CODE in self.attributes
+
+    def Bytes(self):
+        b = b''
+        for attrCode in [DELETED_ATTR_CODE, EXPIRES_AT_ATTR_CODE, NON_INDEXABLE_ATTR_CODE]:
+            if attrCode in self.attributes:
+                b = b+attrCode.to_bytes(1, 'big')
+                if attrCode == EXPIRES_AT_ATTR_CODE:
+                    # The attribute is a datetime. Convert it to epoch integer big endian 64 bit
+                    b = b + \
+                        int(self.attributes[attrCode].replace(tzinfo=datetime.timezone.utc).timestamp()).to_bytes(
+                            8, 'big')
+        return b
diff --git a/immudb/embedded/store/tx.py b/immudb/embedded/store/tx.py
index 4bc1bc1..e3d4faa 100644
--- a/immudb/embedded/store/tx.py
+++ b/immudb/embedded/store/tx.py
@@ -13,46 +13,19 @@
 from immudb.embedded import store, htree
 from immudb.printable import printable
 import hashlib
-from immudb.exceptions import ErrCorruptedData, ErrKeyNotFound
+from immudb.exceptions import ErrCorruptedData, ErrKeyNotFound, ErrMetadataUnsupported
 import sys
 
 
-class Tx(printable):
-    def __init__(self):
-        self.header = None
-        self.entries = None
-        self.htree = None
+def NewTxWithEntries(header: "TxHeader", entries: list) -> "Tx":
 
-    def TxEntryDigest(self):
-        if self.header.version == 0:
-            return TxEntryDigest_v1_1
-        elif self.header.version == 1:
-            return TxEntryDigest_v1_2
-        else:
-            raise ErrCorruptedData
+    _htree = htree.HTree(len(entries))
 
-    def BuildHashTree(self):
-        digests = []
-        txEntryDigest = self.TxEntryDigest()
-        for e in self.entries:
-            digests.append(txEntryDigest(e))
-        self.htree.BuildWith(digests)
-        root = self.htree.root
-        self.header.eh = root
-
-    def IndexOf(self, key: bytes) -> int:
-        kindex = None
-        for k, v in enumerate(self.entries):
-            if v.key() == key:
-                kindex = k
-                break
-        if kindex == None:
-            raise ErrKeyNotFound
-        return k
-
-    def Proof(self, key: bytes):
-        kindex = self.IndexOf(key)
-        return self.htree.InclusionProof(kindex)
+    tx = Tx()
+    tx.header = header
+    tx.entries = entries
+    tx.htree = _htree
+    return tx
 
 
 class TxHeader(printable):
@@ -69,13 +42,6 @@ def __init__(self):
         self.nentries = None
         self.eh = None
 
-    def Alh(self) -> bytes:
-        md = hashlib.sha256()
-        md.update(self.iD.to_bytes(8, 'big'))
-        md.update(self.prevAlh)
-        md.update(self.innerHash())
-        return md.digest()
-
     def innerHash(self) -> bytes:
         md = hashlib.sha256()
         md.update(self.ts.to_bytes(8, 'big'))
@@ -99,14 +65,50 @@ def innerHash(self) -> bytes:
         md.update(self.blRoot)
         return md.digest()
 
+    def Alh(self) -> bytes:
+        md = hashlib.sha256()
+        md.update(self.iD.to_bytes(8, 'big'))
+        md.update(self.prevAlh)
+        md.update(self.innerHash())
+        return md.digest()
+
 
-def NewTxWithEntries(entries: list) -> Tx:
-    tx = Tx()
-    tx.header = TxHeader()
-    tx.header.nentries = len(entries)
-    tx.entries = entries
-    tx.htree = htree.HTree(len(entries))
-    return tx
+class Tx(printable):
+    def __init__(self):
+        self.header = None
+        self.entries = None
+        self.htree = None
+
+    def TxEntryDigest(self):
+        if self.header.version == 0:
+            return TxEntryDigest_v1_1
+        elif self.header.version == 1:
+            return TxEntryDigest_v1_2
+        else:
+            raise ErrCorruptedData
+
+    def BuildHashTree(self):
+        digests = []
+        txEntryDigest = self.TxEntryDigest()
+        for e in self.entries:
+            digests.append(txEntryDigest(e))
+        self.htree.BuildWith(digests)
+        root = self.htree.root
+        self.header.eh = root
+
+    def IndexOf(self, key: bytes) -> int:
+        kindex = None
+        for k, v in enumerate(self.entries):
+            if v.key() == key:
+                kindex = k
+                break
+        if kindex == None:
+            raise ErrKeyNotFound
+        return k
+
+    def Proof(self, key: bytes):
+        kindex = self.IndexOf(key)
+        return self.htree.InclusionProof(kindex)
 
 
 class TxEntry(printable):
@@ -126,6 +128,8 @@ def metadata(self) -> store.KVMetadata:
 
 
 def TxEntryDigest_v1_1(e: TxEntry) -> bytes:
+    if len(e.md.Bytes()) > 0:  # n.b. contrary to Golang, in Pyhton e.md will not be None
+        raise ErrMetadataUnsupported
     md = hashlib.sha256()
     md.update(e.k)
     md.update(e.hVal)
diff --git a/immudb/exceptions.py b/immudb/exceptions.py
index 23d4130..a8ad3fd 100644
--- a/immudb/exceptions.py
+++ b/immudb/exceptions.py
@@ -41,3 +41,7 @@ class ErrReadOnly(Exception):
 
 class ErrKeyNotFound(Exception):
     pass
+
+
+class ErrMetadataUnsupported(Exception):
+    pass
diff --git a/immudb/grpc/proto/schema.proto b/immudb/grpc/proto/schema.proto
index 06cbeae..2a99b08 100644
--- a/immudb/grpc/proto/schema.proto
+++ b/immudb/grpc/proto/schema.proto
@@ -92,6 +92,28 @@ message OpenSessionResponse {
 
 ////////////////////////////////////////////////////////
 
+message Precondition {
+
+	message KeyMustExistPrecondition {
+		bytes key = 1;
+	}
+	
+	message KeyMustNotExistPrecondition {
+		bytes key = 1;
+	}
+	
+	message KeyNotModifiedAfterTXPrecondition {
+		bytes key = 1;
+		uint64 txID = 2;
+	}
+
+	oneof precondition {
+		KeyMustExistPrecondition keyMustExist = 1;
+		KeyMustNotExistPrecondition keyMustNotExist = 2;
+		KeyNotModifiedAfterTXPrecondition keyNotModifiedAfterTX = 3;
+	}
+}
+
 message KeyValue {
 	bytes key = 1;
 	bytes value = 2;
@@ -125,6 +147,7 @@ message Op {
 message ExecAllRequest {
 	repeated Op Operations = 1;
 	bool  noWait = 2;
+	repeated Precondition preconditions = 3;
 }
 
 message Entries {
@@ -204,6 +227,8 @@ message DualProof {
 message Tx {
 	TxHeader header = 1;
 	repeated TxEntry entries = 2;
+	repeated Entry  kvEntries = 3;
+	repeated ZEntry zEntries = 4;
 }
 
 message TxEntry {
@@ -211,11 +236,13 @@ message TxEntry {
 	bytes hValue = 2;
 	int32 vLen = 3;
 	KVMetadata metadata = 4;
+	bytes value = 5; // value must be ignored when len(value) == 0 and vLen > 0. Otherwise, sha256(value) must be equal to hValue
 }
 
 message KVMetadata {
 	bool deleted = 1;
 	Expiration expiration = 2;
+	bool nonIndexable = 3;
 }
 
 message Expiration {
@@ -245,12 +272,14 @@ message InclusionProof {
 message SetRequest {
 	repeated KeyValue KVs = 1;
 	bool  noWait = 2;
+	repeated Precondition preconditions = 3;
 }
 
 message KeyRequest {
 	bytes key = 1;
     uint64 atTx = 2;
 	uint64 sinceTx = 3;
+	bool  noWait = 4;
 }
 
 message KeyListRequest {
@@ -279,6 +308,11 @@ message HealthResponse {
 	string version = 2;
 }
 
+message DatabaseHealthResponse {
+	uint32 pendingRequests = 1;
+	int64 lastRequestCompletedAt = 2;
+}
+
 message ImmutableState {
 	string db = 1;
 	uint64 txId = 2;
@@ -292,6 +326,7 @@ message ReferenceRequest {
 	uint64 atTx = 3;
 	bool boundRef = 4;
 	bool  noWait = 5;
+	repeated Precondition preconditions = 6;
 }
 
 message VerifiableReferenceRequest {
@@ -340,18 +375,44 @@ message VerifiableZAddRequest {
 }
 
 message TxRequest {
-	uint64 tx = 1;
+	uint64      tx = 1;
+	EntriesSpec entriesSpec = 2;
+	uint64 sinceTx  = 3;
+	bool   noWait   = 4;
+}
+
+message EntriesSpec {
+	EntryTypeSpec kvEntriesSpec  = 1;
+	EntryTypeSpec zEntriesSpec   = 2;
+	EntryTypeSpec sqlEntriesSpec = 3;
+}
+
+message EntryTypeSpec {
+	EntryTypeAction action = 1;
+}
+
+enum EntryTypeAction {
+	EXCLUDE     = 0;
+	ONLY_DIGEST = 1;
+	RAW_VALUE   = 2;
+	RESOLVE     = 3;
 }
 
 message VerifiableTxRequest {
 	uint64 tx = 1;
 	uint64 proveSinceTx = 2;
+	EntriesSpec entriesSpec = 3;
+	uint64 sinceTx  = 4;
+	bool   noWait   = 5;
 }
 
 message TxScanRequest {
 	uint64 initialTx = 1;
 	uint32 limit = 2;
     bool   desc = 3;
+	EntriesSpec entriesSpec = 4;
+	uint64 sinceTx  = 5;
+	bool   noWait   = 6;
 }
 
 message TxList {
@@ -364,19 +425,156 @@ message Database {
 
 message DatabaseSettings {
 	string databaseName = 1;
+
 	bool   replica = 2;
 	string masterDatabase = 3;
 	string masterAddress = 4;
 	uint32 masterPort = 5;
 	string followerUsername = 6;
 	string followerPassword = 7;
+
 	uint32 fileSize = 8;
 	uint32 maxKeyLen = 9;
 	uint32 maxValueLen = 10;
 	uint32 maxTxEntries = 11;
+
 	bool   excludeCommitTime = 12;
 }
 
+message CreateDatabaseRequest {
+	string name = 1;
+	DatabaseNullableSettings settings = 2;
+}
+
+message CreateDatabaseResponse {
+	string name = 1;
+	DatabaseNullableSettings settings = 2;
+}
+
+message UpdateDatabaseRequest {
+	string database = 1;
+	DatabaseNullableSettings settings = 2;
+}
+
+message UpdateDatabaseResponse {	// Reserved to reply with more advanced response later
+	string database = 1;
+	DatabaseNullableSettings settings = 2;
+}
+
+message DatabaseSettingsRequest {
+
+}
+
+message DatabaseSettingsResponse {
+	string database = 1;
+	DatabaseNullableSettings settings = 2;
+}
+
+message NullableUint32 {
+	uint32 value = 1;
+}
+
+message NullableUint64 {
+	uint64 value = 1;
+}
+
+message NullableFloat {
+	float value = 1;
+}
+
+message NullableBool {
+	bool value = 1;
+}
+
+message NullableString {
+	string value = 1;
+}
+
+message DatabaseNullableSettings {
+	ReplicationNullableSettings replicationSettings = 2;
+
+	NullableUint32 fileSize = 8;
+	NullableUint32 maxKeyLen = 9;
+	NullableUint32 maxValueLen = 10;
+	NullableUint32 maxTxEntries = 11;
+
+	NullableBool excludeCommitTime = 12;
+
+	NullableUint32 maxConcurrency = 13;
+	NullableUint32 maxIOConcurrency = 14;
+
+	NullableUint32 txLogCacheSize = 15;
+	NullableUint32 vLogMaxOpenedFiles = 16;
+	NullableUint32 txLogMaxOpenedFiles = 17;
+	NullableUint32 commitLogMaxOpenedFiles = 18;
+
+	IndexNullableSettings indexSettings = 19;
+
+	NullableUint32 writeTxHeaderVersion = 20;
+	
+	NullableBool autoload = 21;
+}
+
+message ReplicationNullableSettings {
+	NullableBool   replica = 1;
+	NullableString masterDatabase = 2;
+	NullableString masterAddress = 3;
+	NullableUint32 masterPort = 4;
+	NullableString followerUsername = 5;
+	NullableString followerPassword = 6;
+}
+
+message IndexNullableSettings {
+	NullableUint32  flushThreshold = 1;
+	NullableUint32  syncThreshold = 2;
+	NullableUint32  cacheSize = 3;
+	NullableUint32  maxNodeSize = 4;
+	NullableUint32  maxActiveSnapshots = 5;
+	NullableUint64  renewSnapRootAfter = 6;
+	NullableUint32  compactionThld = 7;
+	NullableUint32  delayDuringCompaction = 8;
+	NullableUint32  nodesLogMaxOpenedFiles = 9;
+	NullableUint32  historyLogMaxOpenedFiles = 10;
+	NullableUint32  commitLogMaxOpenedFiles = 11;
+	NullableUint32  flushBufferSize = 12;
+	NullableFloat   cleanupPercentage = 13;
+}
+
+message LoadDatabaseRequest {
+	string database = 1;
+	// may add createIfNotExist
+}
+
+message LoadDatabaseResponse {
+	string database = 1;
+	// may add setttings
+}
+
+message UnloadDatabaseRequest {
+	string database = 1;
+}
+
+message UnloadDatabaseResponse {
+	string database = 1;
+}
+
+message DeleteDatabaseRequest {
+	string database = 1;
+}
+
+message DeleteDatabaseResponse {
+	string database = 1;
+}
+
+message FlushIndexRequest {
+	float  cleanupPercentage = 1;
+	bool   synced = 2;
+}
+
+message FlushIndexResponse {
+	string database = 1;
+}
+
 message Table {
 	string tableName = 1;
 }
@@ -435,10 +633,23 @@ message SetActiveUserRequest {
 	string username = 2;
 }
 
-message DatabaseListResponse{
+message DatabaseListResponse {
 	repeated Database databases = 1;
 }
 
+message DatabaseListRequestV2 {
+}
+
+message DatabaseListResponseV2 {
+	repeated DatabaseWithSettings databases = 1;
+}
+
+message DatabaseWithSettings {
+	string name = 1;
+	DatabaseNullableSettings settings = 2;
+	bool loaded = 3;
+}
+
 message Chunk {
 	bytes content = 1;
 }
@@ -536,6 +747,8 @@ service ImmuService {
 	rpc ListUsers (google.protobuf.Empty) returns (UserList);
 	rpc CreateUser (CreateUserRequest) returns (google.protobuf.Empty);
 	rpc ChangePassword (ChangePasswordRequest) returns (google.protobuf.Empty);
+	rpc ChangePermission(ChangePermissionRequest) returns (google.protobuf.Empty);
+	rpc SetActiveUser (SetActiveUserRequest) returns (google.protobuf.Empty);
 	rpc UpdateAuthConfig (AuthConfig) returns (google.protobuf.Empty); // DEPRECATED
 	rpc UpdateMTLSConfig (MTLSConfig) returns (google.protobuf.Empty); // DEPRECATED
 
@@ -566,12 +779,12 @@ service ImmuService {
 
 	// NOT YET SUPPORTED
 	rpc CountAll(google.protobuf.Empty) returns (EntryCount);
-
 	rpc TxById(TxRequest) returns (Tx);
 	rpc VerifiableTxById(VerifiableTxRequest) returns (VerifiableTx);
 	rpc TxScan(TxScanRequest) returns (TxList);
 	rpc History(HistoryRequest) returns (Entries);
 	rpc Health (google.protobuf.Empty) returns (HealthResponse);
+	rpc DatabaseHealth (google.protobuf.Empty) returns (DatabaseHealthResponse);
 	rpc CurrentState (google.protobuf.Empty) returns (ImmutableState);
 	rpc SetReference (ReferenceRequest) returns (TxHeader);
 	rpc VerifiableSetReference (VerifiableReferenceRequest) returns (VerifiableTx);
@@ -581,14 +794,21 @@ service ImmuService {
 
 	// DEPRECATED: kept for backward compatibility
 	rpc CreateDatabase(Database) returns (google.protobuf.Empty);
-
 	rpc CreateDatabaseWith(DatabaseSettings) returns (google.protobuf.Empty);
+	rpc CreateDatabaseV2(CreateDatabaseRequest) returns (CreateDatabaseResponse);
+	rpc LoadDatabase(LoadDatabaseRequest) returns (LoadDatabaseResponse);
+	rpc UnloadDatabase(UnloadDatabaseRequest) returns (UnloadDatabaseResponse);
+	rpc DeleteDatabase(DeleteDatabaseRequest) returns (DeleteDatabaseResponse);
 	rpc DatabaseList (google.protobuf.Empty) returns (DatabaseListResponse);
+	rpc DatabaseListV2 (DatabaseListRequestV2) returns (DatabaseListResponseV2);
 	rpc UseDatabase(Database) returns (UseDatabaseReply);
 	rpc UpdateDatabase(DatabaseSettings) returns (google.protobuf.Empty);
+	rpc UpdateDatabaseV2(UpdateDatabaseRequest) returns (UpdateDatabaseResponse);
+	rpc GetDatabaseSettings(google.protobuf.Empty) returns (DatabaseSettings);
+	rpc GetDatabaseSettingsV2(DatabaseSettingsRequest) returns (DatabaseSettingsResponse);
+	rpc FlushIndex(FlushIndexRequest) returns (FlushIndexResponse);
 	rpc CompactIndex(google.protobuf.Empty) returns (google.protobuf.Empty);
-	rpc ChangePermission(ChangePermissionRequest) returns (google.protobuf.Empty);
-	rpc SetActiveUser (SetActiveUserRequest) returns (google.protobuf.Empty);
+
 	// Streams
 	rpc streamGet(KeyRequest) returns (stream Chunk) {};
 	rpc streamSet(stream Chunk) returns (TxHeader) {};
@@ -600,7 +820,7 @@ service ImmuService {
 	rpc streamExecAll(stream Chunk) returns (TxHeader) {};
 
 	// Replication
-	rpc exportTx(TxRequest) returns (stream Chunk) {};
+	rpc exportTx(ExportTxRequest) returns (stream Chunk) {};
 	rpc replicateTx(stream Chunk) returns (TxHeader) {};
 
 	rpc SQLExec(SQLExecRequest) returns (SQLExecResult);
diff --git a/immudb/grpc/schema_pb2.py b/immudb/grpc/schema_pb2.py
index 7cb5578..c4655d0 100644
--- a/immudb/grpc/schema_pb2.py
+++ b/immudb/grpc/schema_pb2.py
@@ -17,7 +17,7 @@
 from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2
 
 
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cschema.proto\x12\rimmudb.schema\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1cgoogle/protobuf/struct.proto\"\x12\n\x03Key\x12\x0b\n\x03key\x18\x01 \x01(\x0c\"2\n\nPermission\x12\x10\n\x08\x64\x61tabase\x18\x01 \x01(\t\x12\x12\n\npermission\x18\x02 \x01(\r\"z\n\x04User\x12\x0c\n\x04user\x18\x01 \x01(\x0c\x12.\n\x0bpermissions\x18\x03 \x03(\x0b\x32\x19.immudb.schema.Permission\x12\x11\n\tcreatedby\x18\x04 \x01(\t\x12\x11\n\tcreatedat\x18\x05 \x01(\t\x12\x0e\n\x06\x61\x63tive\x18\x06 \x01(\x08\".\n\x08UserList\x12\"\n\x05users\x18\x01 \x03(\x0b\x32\x13.immudb.schema.User\"Y\n\x11\x43reateUserRequest\x12\x0c\n\x04user\x18\x01 \x01(\x0c\x12\x10\n\x08password\x18\x02 \x01(\x0c\x12\x12\n\npermission\x18\x03 \x01(\r\x12\x10\n\x08\x64\x61tabase\x18\x04 \x01(\t\"\x1b\n\x0bUserRequest\x12\x0c\n\x04user\x18\x01 \x01(\x0c\"O\n\x15\x43hangePasswordRequest\x12\x0c\n\x04user\x18\x01 \x01(\x0c\x12\x13\n\x0boldPassword\x18\x02 \x01(\x0c\x12\x13\n\x0bnewPassword\x18\x03 \x01(\x0c\".\n\x0cLoginRequest\x12\x0c\n\x04user\x18\x01 \x01(\x0c\x12\x10\n\x08password\x18\x02 \x01(\x0c\"/\n\rLoginResponse\x12\r\n\x05token\x18\x01 \x01(\t\x12\x0f\n\x07warning\x18\x02 \x01(\x0c\"\x1a\n\nAuthConfig\x12\x0c\n\x04kind\x18\x01 \x01(\r\"\x1d\n\nMTLSConfig\x12\x0f\n\x07\x65nabled\x18\x01 \x01(\x08\"N\n\x12OpenSessionRequest\x12\x10\n\x08username\x18\x01 \x01(\x0c\x12\x10\n\x08password\x18\x02 \x01(\x0c\x12\x14\n\x0c\x64\x61tabaseName\x18\x03 \x01(\t\"<\n\x13OpenSessionResponse\x12\x11\n\tsessionID\x18\x01 \x01(\t\x12\x12\n\nserverUUID\x18\x02 \x01(\t\"S\n\x08KeyValue\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\r\n\x05value\x18\x02 \x01(\x0c\x12+\n\x08metadata\x18\x03 \x01(\x0b\x32\x19.immudb.schema.KVMetadata\"\x9d\x01\n\x05\x45ntry\x12\n\n\x02tx\x18\x01 \x01(\x04\x12\x0b\n\x03key\x18\x02 \x01(\x0c\x12\r\n\x05value\x18\x03 \x01(\x0c\x12.\n\x0creferencedBy\x18\x04 \x01(\x0b\x32\x18.immudb.schema.Reference\x12+\n\x08metadata\x18\x05 \x01(\x0b\x32\x19.immudb.schema.KVMetadata\x12\x0f\n\x07\x65xpired\x18\x06 \x01(\x08\"_\n\tReference\x12\n\n\x02tx\x18\x01 \x01(\x04\x12\x0b\n\x03key\x18\x02 \x01(\x0c\x12\x0c\n\x04\x61tTx\x18\x03 \x01(\x04\x12+\n\x08metadata\x18\x04 \x01(\x0b\x32\x19.immudb.schema.KVMetadata\"\x94\x01\n\x02Op\x12%\n\x02kv\x18\x01 \x01(\x0b\x32\x17.immudb.schema.KeyValueH\x00\x12*\n\x04zAdd\x18\x02 \x01(\x0b\x32\x1a.immudb.schema.ZAddRequestH\x00\x12.\n\x03ref\x18\x03 \x01(\x0b\x32\x1f.immudb.schema.ReferenceRequestH\x00\x42\x0b\n\toperation\"G\n\x0e\x45xecAllRequest\x12%\n\nOperations\x18\x01 \x03(\x0b\x32\x11.immudb.schema.Op\x12\x0e\n\x06noWait\x18\x02 \x01(\x08\"0\n\x07\x45ntries\x12%\n\x07\x65ntries\x18\x01 \x03(\x0b\x32\x14.immudb.schema.Entry\"d\n\x06ZEntry\x12\x0b\n\x03set\x18\x01 \x01(\x0c\x12\x0b\n\x03key\x18\x02 \x01(\x0c\x12#\n\x05\x65ntry\x18\x03 \x01(\x0b\x32\x14.immudb.schema.Entry\x12\r\n\x05score\x18\x04 \x01(\x01\x12\x0c\n\x04\x61tTx\x18\x05 \x01(\x04\"2\n\x08ZEntries\x12&\n\x07\x65ntries\x18\x01 \x03(\x0b\x32\x15.immudb.schema.ZEntry\"l\n\x0bScanRequest\x12\x0f\n\x07seekKey\x18\x01 \x01(\x0c\x12\x0e\n\x06prefix\x18\x02 \x01(\x0c\x12\x0c\n\x04\x64\x65sc\x18\x03 \x01(\x08\x12\r\n\x05limit\x18\x04 \x01(\x04\x12\x0f\n\x07sinceTx\x18\x05 \x01(\x04\x12\x0e\n\x06noWait\x18\x06 \x01(\x08\"\x1b\n\tKeyPrefix\x12\x0e\n\x06prefix\x18\x01 \x01(\x0c\"\x1b\n\nEntryCount\x12\r\n\x05\x63ount\x18\x01 \x01(\x04\"1\n\tSignature\x12\x11\n\tpublicKey\x18\x01 \x01(\x0c\x12\x11\n\tsignature\x18\x02 \x01(\x0c\"\xaf\x01\n\x08TxHeader\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x0f\n\x07prevAlh\x18\x02 \x01(\x0c\x12\n\n\x02ts\x18\x03 \x01(\x03\x12\x10\n\x08nentries\x18\x04 \x01(\x05\x12\n\n\x02\x65H\x18\x05 \x01(\x0c\x12\x0e\n\x06\x62lTxId\x18\x06 \x01(\x04\x12\x0e\n\x06\x62lRoot\x18\x07 \x01(\x0c\x12\x0f\n\x07version\x18\x08 \x01(\x05\x12+\n\x08metadata\x18\t \x01(\x0b\x32\x19.immudb.schema.TxMetadata\"\x0c\n\nTxMetadata\"D\n\x0bLinearProof\x12\x12\n\nsourceTxId\x18\x01 \x01(\x04\x12\x12\n\nTargetTxId\x18\x02 \x01(\x04\x12\r\n\x05terms\x18\x03 \x03(\x0c\"\x83\x02\n\tDualProof\x12/\n\x0esourceTxHeader\x18\x01 \x01(\x0b\x32\x17.immudb.schema.TxHeader\x12/\n\x0etargetTxHeader\x18\x02 \x01(\x0b\x32\x17.immudb.schema.TxHeader\x12\x16\n\x0einclusionProof\x18\x03 \x03(\x0c\x12\x18\n\x10\x63onsistencyProof\x18\x04 \x03(\x0c\x12\x15\n\rtargetBlTxAlh\x18\x05 \x01(\x0c\x12\x1a\n\x12lastInclusionProof\x18\x06 \x03(\x0c\x12/\n\x0blinearProof\x18\x07 \x01(\x0b\x32\x1a.immudb.schema.LinearProof\"V\n\x02Tx\x12\'\n\x06header\x18\x01 \x01(\x0b\x32\x17.immudb.schema.TxHeader\x12\'\n\x07\x65ntries\x18\x02 \x03(\x0b\x32\x16.immudb.schema.TxEntry\"a\n\x07TxEntry\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\x0e\n\x06hValue\x18\x02 \x01(\x0c\x12\x0c\n\x04vLen\x18\x03 \x01(\x05\x12+\n\x08metadata\x18\x04 \x01(\x0b\x32\x19.immudb.schema.KVMetadata\"L\n\nKVMetadata\x12\x0f\n\x07\x64\x65leted\x18\x01 \x01(\x08\x12-\n\nexpiration\x18\x02 \x01(\x0b\x32\x19.immudb.schema.Expiration\"\x1f\n\nExpiration\x12\x11\n\texpiresAt\x18\x01 \x01(\x03\"\x87\x01\n\x0cVerifiableTx\x12\x1d\n\x02tx\x18\x01 \x01(\x0b\x32\x11.immudb.schema.Tx\x12+\n\tdualProof\x18\x02 \x01(\x0b\x32\x18.immudb.schema.DualProof\x12+\n\tsignature\x18\x03 \x01(\x0b\x32\x18.immudb.schema.Signature\"\xa0\x01\n\x0fVerifiableEntry\x12#\n\x05\x65ntry\x18\x01 \x01(\x0b\x32\x14.immudb.schema.Entry\x12\x31\n\x0cverifiableTx\x18\x02 \x01(\x0b\x32\x1b.immudb.schema.VerifiableTx\x12\x35\n\x0einclusionProof\x18\x03 \x01(\x0b\x32\x1d.immudb.schema.InclusionProof\"<\n\x0eInclusionProof\x12\x0c\n\x04leaf\x18\x01 \x01(\x05\x12\r\n\x05width\x18\x02 \x01(\x05\x12\r\n\x05terms\x18\x03 \x03(\x0c\"B\n\nSetRequest\x12$\n\x03KVs\x18\x01 \x03(\x0b\x32\x17.immudb.schema.KeyValue\x12\x0e\n\x06noWait\x18\x02 \x01(\x08\"8\n\nKeyRequest\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\x0c\n\x04\x61tTx\x18\x02 \x01(\x04\x12\x0f\n\x07sinceTx\x18\x03 \x01(\x04\"/\n\x0eKeyListRequest\x12\x0c\n\x04keys\x18\x01 \x03(\x0c\x12\x0f\n\x07sinceTx\x18\x02 \x01(\x04\"B\n\x11\x44\x65leteKeysRequest\x12\x0c\n\x04keys\x18\x01 \x03(\x0c\x12\x0f\n\x07sinceTx\x18\x02 \x01(\x04\x12\x0e\n\x06noWait\x18\x03 \x01(\x08\"[\n\x14VerifiableSetRequest\x12-\n\nsetRequest\x18\x01 \x01(\x0b\x32\x19.immudb.schema.SetRequest\x12\x14\n\x0cproveSinceTx\x18\x02 \x01(\x04\"[\n\x14VerifiableGetRequest\x12-\n\nkeyRequest\x18\x01 \x01(\x0b\x32\x19.immudb.schema.KeyRequest\x12\x14\n\x0cproveSinceTx\x18\x02 \x01(\x04\"1\n\x0eHealthResponse\x12\x0e\n\x06status\x18\x01 \x01(\x08\x12\x0f\n\x07version\x18\x02 \x01(\t\"g\n\x0eImmutableState\x12\n\n\x02\x64\x62\x18\x01 \x01(\t\x12\x0c\n\x04txId\x18\x02 \x01(\x04\x12\x0e\n\x06txHash\x18\x03 \x01(\x0c\x12+\n\tsignature\x18\x04 \x01(\x0b\x32\x18.immudb.schema.Signature\"f\n\x10ReferenceRequest\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\x15\n\rreferencedKey\x18\x02 \x01(\x0c\x12\x0c\n\x04\x61tTx\x18\x03 \x01(\x04\x12\x10\n\x08\x62oundRef\x18\x04 \x01(\x08\x12\x0e\n\x06noWait\x18\x05 \x01(\x08\"m\n\x1aVerifiableReferenceRequest\x12\x39\n\x10referenceRequest\x18\x01 \x01(\x0b\x32\x1f.immudb.schema.ReferenceRequest\x12\x14\n\x0cproveSinceTx\x18\x02 \x01(\x04\"f\n\x0bZAddRequest\x12\x0b\n\x03set\x18\x01 \x01(\x0c\x12\r\n\x05score\x18\x02 \x01(\x01\x12\x0b\n\x03key\x18\x03 \x01(\x0c\x12\x0c\n\x04\x61tTx\x18\x04 \x01(\x04\x12\x10\n\x08\x62oundRef\x18\x05 \x01(\x08\x12\x0e\n\x06noWait\x18\x06 \x01(\x08\"\x16\n\x05Score\x12\r\n\x05score\x18\x01 \x01(\x01\"\xf6\x01\n\x0cZScanRequest\x12\x0b\n\x03set\x18\x01 \x01(\x0c\x12\x0f\n\x07seekKey\x18\x02 \x01(\x0c\x12\x11\n\tseekScore\x18\x03 \x01(\x01\x12\x10\n\x08seekAtTx\x18\x04 \x01(\x04\x12\x15\n\rinclusiveSeek\x18\x05 \x01(\x08\x12\r\n\x05limit\x18\x06 \x01(\x04\x12\x0c\n\x04\x64\x65sc\x18\x07 \x01(\x08\x12&\n\x08minScore\x18\x08 \x01(\x0b\x32\x14.immudb.schema.Score\x12&\n\x08maxScore\x18\t \x01(\x0b\x32\x14.immudb.schema.Score\x12\x0f\n\x07sinceTx\x18\n \x01(\x04\x12\x0e\n\x06noWait\x18\x0b \x01(\x08\"[\n\x0eHistoryRequest\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\x0e\n\x06offset\x18\x02 \x01(\x04\x12\r\n\x05limit\x18\x03 \x01(\x05\x12\x0c\n\x04\x64\x65sc\x18\x04 \x01(\x08\x12\x0f\n\x07sinceTx\x18\x05 \x01(\x04\"^\n\x15VerifiableZAddRequest\x12/\n\x0bzAddRequest\x18\x01 \x01(\x0b\x32\x1a.immudb.schema.ZAddRequest\x12\x14\n\x0cproveSinceTx\x18\x02 \x01(\x04\"\x17\n\tTxRequest\x12\n\n\x02tx\x18\x01 \x01(\x04\"7\n\x13VerifiableTxRequest\x12\n\n\x02tx\x18\x01 \x01(\x04\x12\x14\n\x0cproveSinceTx\x18\x02 \x01(\x04\"?\n\rTxScanRequest\x12\x11\n\tinitialTx\x18\x01 \x01(\x04\x12\r\n\x05limit\x18\x02 \x01(\r\x12\x0c\n\x04\x64\x65sc\x18\x03 \x01(\x08\"(\n\x06TxList\x12\x1e\n\x03txs\x18\x01 \x03(\x0b\x32\x11.immudb.schema.Tx\" \n\x08\x44\x61tabase\x12\x14\n\x0c\x64\x61tabaseName\x18\x01 \x01(\t\"\x9b\x02\n\x10\x44\x61tabaseSettings\x12\x14\n\x0c\x64\x61tabaseName\x18\x01 \x01(\t\x12\x0f\n\x07replica\x18\x02 \x01(\x08\x12\x16\n\x0emasterDatabase\x18\x03 \x01(\t\x12\x15\n\rmasterAddress\x18\x04 \x01(\t\x12\x12\n\nmasterPort\x18\x05 \x01(\r\x12\x18\n\x10\x66ollowerUsername\x18\x06 \x01(\t\x12\x18\n\x10\x66ollowerPassword\x18\x07 \x01(\t\x12\x10\n\x08\x66ileSize\x18\x08 \x01(\r\x12\x11\n\tmaxKeyLen\x18\t \x01(\r\x12\x13\n\x0bmaxValueLen\x18\n \x01(\r\x12\x14\n\x0cmaxTxEntries\x18\x0b \x01(\r\x12\x19\n\x11\x65xcludeCommitTime\x18\x0c \x01(\x08\"\x1a\n\x05Table\x12\x11\n\ttableName\x18\x01 \x01(\t\"h\n\rSQLGetRequest\x12\r\n\x05table\x18\x01 \x01(\t\x12)\n\x08pkValues\x18\x02 \x03(\x0b\x32\x17.immudb.schema.SQLValue\x12\x0c\n\x04\x61tTx\x18\x03 \x01(\x04\x12\x0f\n\x07sinceTx\x18\x04 \x01(\x04\"d\n\x17VerifiableSQLGetRequest\x12\x33\n\rsqlGetRequest\x18\x01 \x01(\x0b\x32\x1c.immudb.schema.SQLGetRequest\x12\x14\n\x0cproveSinceTx\x18\x02 \x01(\x04\"_\n\x08SQLEntry\x12\n\n\x02tx\x18\x01 \x01(\x04\x12\x0b\n\x03key\x18\x02 \x01(\x0c\x12\r\n\x05value\x18\x03 \x01(\x0c\x12+\n\x08metadata\x18\x04 \x01(\x0b\x32\x19.immudb.schema.KVMetadata\"\xdd\x05\n\x12VerifiableSQLEntry\x12)\n\x08sqlEntry\x18\x01 \x01(\x0b\x32\x17.immudb.schema.SQLEntry\x12\x31\n\x0cverifiableTx\x18\x02 \x01(\x0b\x32\x1b.immudb.schema.VerifiableTx\x12\x35\n\x0einclusionProof\x18\x03 \x01(\x0b\x32\x1d.immudb.schema.InclusionProof\x12\x12\n\nDatabaseId\x18\x04 \x01(\r\x12\x0f\n\x07TableId\x18\x05 \x01(\r\x12\r\n\x05PKIDs\x18\x10 \x03(\r\x12I\n\x0c\x43olNamesById\x18\x08 \x03(\x0b\x32\x33.immudb.schema.VerifiableSQLEntry.ColNamesByIdEntry\x12I\n\x0c\x43olIdsByName\x18\t \x03(\x0b\x32\x33.immudb.schema.VerifiableSQLEntry.ColIdsByNameEntry\x12I\n\x0c\x43olTypesById\x18\n \x03(\x0b\x32\x33.immudb.schema.VerifiableSQLEntry.ColTypesByIdEntry\x12\x45\n\nColLenById\x18\x0b \x03(\x0b\x32\x31.immudb.schema.VerifiableSQLEntry.ColLenByIdEntry\x1a\x33\n\x11\x43olNamesByIdEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x33\n\x11\x43olIdsByNameEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\r:\x02\x38\x01\x1a\x33\n\x11\x43olTypesByIdEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x31\n\x0f\x43olLenByIdEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01J\x04\x08\x06\x10\x07\"!\n\x10UseDatabaseReply\x12\r\n\x05token\x18\x01 \x01(\t\"\x82\x01\n\x17\x43hangePermissionRequest\x12/\n\x06\x61\x63tion\x18\x01 \x01(\x0e\x32\x1f.immudb.schema.PermissionAction\x12\x10\n\x08username\x18\x02 \x01(\t\x12\x10\n\x08\x64\x61tabase\x18\x03 \x01(\t\x12\x12\n\npermission\x18\x04 \x01(\r\"8\n\x14SetActiveUserRequest\x12\x0e\n\x06\x61\x63tive\x18\x01 \x01(\x08\x12\x10\n\x08username\x18\x02 \x01(\t\"B\n\x14\x44\x61tabaseListResponse\x12*\n\tdatabases\x18\x01 \x03(\x0b\x32\x17.immudb.schema.Database\"\x18\n\x05\x43hunk\x12\x0f\n\x07\x63ontent\x18\x01 \x01(\x0c\"9\n\x12UseSnapshotRequest\x12\x0f\n\x07sinceTx\x18\x01 \x01(\x04\x12\x12\n\nasBeforeTx\x18\x02 \x01(\x04\"X\n\x0eSQLExecRequest\x12\x0b\n\x03sql\x18\x01 \x01(\t\x12)\n\x06params\x18\x02 \x03(\x0b\x32\x19.immudb.schema.NamedParam\x12\x0e\n\x06noWait\x18\x03 \x01(\x08\"`\n\x0fSQLQueryRequest\x12\x0b\n\x03sql\x18\x01 \x01(\t\x12)\n\x06params\x18\x02 \x03(\x0b\x32\x19.immudb.schema.NamedParam\x12\x15\n\rreuseSnapshot\x18\x03 \x01(\x08\"B\n\nNamedParam\x12\x0c\n\x04name\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.immudb.schema.SQLValue\"N\n\rSQLExecResult\x12*\n\x03txs\x18\x05 \x03(\x0b\x32\x1d.immudb.schema.CommittedSQLTx\x12\x11\n\tongoingTx\x18\x06 \x01(\x08\"\x8d\x03\n\x0e\x43ommittedSQLTx\x12\'\n\x06header\x18\x01 \x01(\x0b\x32\x17.immudb.schema.TxHeader\x12\x13\n\x0bupdatedRows\x18\x02 \x01(\r\x12K\n\x0flastInsertedPKs\x18\x03 \x03(\x0b\x32\x32.immudb.schema.CommittedSQLTx.LastInsertedPKsEntry\x12M\n\x10\x66irstInsertedPKs\x18\x04 \x03(\x0b\x32\x33.immudb.schema.CommittedSQLTx.FirstInsertedPKsEntry\x1aO\n\x14LastInsertedPKsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.immudb.schema.SQLValue:\x02\x38\x01\x1aP\n\x15\x46irstInsertedPKsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.immudb.schema.SQLValue:\x02\x38\x01\"Z\n\x0eSQLQueryResult\x12&\n\x07\x63olumns\x18\x02 \x03(\x0b\x32\x15.immudb.schema.Column\x12 \n\x04rows\x18\x01 \x03(\x0b\x32\x12.immudb.schema.Row\"$\n\x06\x43olumn\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04type\x18\x02 \x01(\t\"?\n\x03Row\x12\x0f\n\x07\x63olumns\x18\x01 \x03(\t\x12\'\n\x06values\x18\x02 \x03(\x0b\x32\x17.immudb.schema.SQLValue\"\x82\x01\n\x08SQLValue\x12*\n\x04null\x18\x01 \x01(\x0e\x32\x1a.google.protobuf.NullValueH\x00\x12\x0b\n\x01n\x18\x02 \x01(\x03H\x00\x12\x0b\n\x01s\x18\x03 \x01(\tH\x00\x12\x0b\n\x01\x62\x18\x04 \x01(\x08H\x00\x12\x0c\n\x02\x62s\x18\x05 \x01(\x0cH\x00\x12\x0c\n\x02ts\x18\x06 \x01(\x03H\x00\x42\x07\n\x05value\"3\n\x0cNewTxRequest\x12#\n\x04mode\x18\x01 \x01(\x0e\x32\x15.immudb.schema.TxMode\"&\n\rNewTxResponse\x12\x15\n\rtransactionID\x18\x01 \x01(\t\"(\n\tErrorInfo\x12\x0c\n\x04\x63ode\x18\x01 \x01(\t\x12\r\n\x05\x63\x61use\x18\x02 \x01(\t\"\x1a\n\tDebugInfo\x12\r\n\x05stack\x18\x01 \x01(\t\" \n\tRetryInfo\x12\x13\n\x0bretry_delay\x18\x01 \x01(\x05*)\n\x10PermissionAction\x12\t\n\x05GRANT\x10\x00\x12\n\n\x06REVOKE\x10\x01*4\n\x06TxMode\x12\x0c\n\x08ReadOnly\x10\x00\x12\r\n\tWriteOnly\x10\x01\x12\r\n\tReadWrite\x10\x02\x32\xe6 \n\x0bImmuService\x12<\n\tListUsers\x12\x16.google.protobuf.Empty\x1a\x17.immudb.schema.UserList\x12\x46\n\nCreateUser\x12 .immudb.schema.CreateUserRequest\x1a\x16.google.protobuf.Empty\x12N\n\x0e\x43hangePassword\x12$.immudb.schema.ChangePasswordRequest\x1a\x16.google.protobuf.Empty\x12\x45\n\x10UpdateAuthConfig\x12\x19.immudb.schema.AuthConfig\x1a\x16.google.protobuf.Empty\x12\x45\n\x10UpdateMTLSConfig\x12\x19.immudb.schema.MTLSConfig\x1a\x16.google.protobuf.Empty\x12V\n\x0bOpenSession\x12!.immudb.schema.OpenSessionRequest\x1a\".immudb.schema.OpenSessionResponse\"\x00\x12@\n\x0c\x43loseSession\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\"\x00\x12=\n\tKeepAlive\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\"\x00\x12\x44\n\x05NewTx\x12\x1b.immudb.schema.NewTxRequest\x1a\x1c.immudb.schema.NewTxResponse\"\x00\x12\x41\n\x06\x43ommit\x12\x16.google.protobuf.Empty\x1a\x1d.immudb.schema.CommittedSQLTx\"\x00\x12<\n\x08Rollback\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\"\x00\x12\x44\n\tTxSQLExec\x12\x1d.immudb.schema.SQLExecRequest\x1a\x16.google.protobuf.Empty\"\x00\x12M\n\nTxSQLQuery\x12\x1e.immudb.schema.SQLQueryRequest\x1a\x1d.immudb.schema.SQLQueryResult\"\x00\x12\x42\n\x05Login\x12\x1b.immudb.schema.LoginRequest\x1a\x1c.immudb.schema.LoginResponse\x12\x38\n\x06Logout\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\x12\x39\n\x03Set\x12\x19.immudb.schema.SetRequest\x1a\x17.immudb.schema.TxHeader\x12Q\n\rVerifiableSet\x12#.immudb.schema.VerifiableSetRequest\x1a\x1b.immudb.schema.VerifiableTx\x12\x36\n\x03Get\x12\x19.immudb.schema.KeyRequest\x1a\x14.immudb.schema.Entry\x12T\n\rVerifiableGet\x12#.immudb.schema.VerifiableGetRequest\x1a\x1e.immudb.schema.VerifiableEntry\x12\x43\n\x06\x44\x65lete\x12 .immudb.schema.DeleteKeysRequest\x1a\x17.immudb.schema.TxHeader\x12?\n\x06GetAll\x12\x1d.immudb.schema.KeyListRequest\x1a\x16.immudb.schema.Entries\x12\x41\n\x07\x45xecAll\x12\x1d.immudb.schema.ExecAllRequest\x1a\x17.immudb.schema.TxHeader\x12:\n\x04Scan\x12\x1a.immudb.schema.ScanRequest\x1a\x16.immudb.schema.Entries\x12<\n\x05\x43ount\x12\x18.immudb.schema.KeyPrefix\x1a\x19.immudb.schema.EntryCount\x12=\n\x08\x43ountAll\x12\x16.google.protobuf.Empty\x1a\x19.immudb.schema.EntryCount\x12\x35\n\x06TxById\x12\x18.immudb.schema.TxRequest\x1a\x11.immudb.schema.Tx\x12S\n\x10VerifiableTxById\x12\".immudb.schema.VerifiableTxRequest\x1a\x1b.immudb.schema.VerifiableTx\x12=\n\x06TxScan\x12\x1c.immudb.schema.TxScanRequest\x1a\x15.immudb.schema.TxList\x12@\n\x07History\x12\x1d.immudb.schema.HistoryRequest\x1a\x16.immudb.schema.Entries\x12?\n\x06Health\x12\x16.google.protobuf.Empty\x1a\x1d.immudb.schema.HealthResponse\x12\x45\n\x0c\x43urrentState\x12\x16.google.protobuf.Empty\x1a\x1d.immudb.schema.ImmutableState\x12H\n\x0cSetReference\x12\x1f.immudb.schema.ReferenceRequest\x1a\x17.immudb.schema.TxHeader\x12`\n\x16VerifiableSetReference\x12).immudb.schema.VerifiableReferenceRequest\x1a\x1b.immudb.schema.VerifiableTx\x12;\n\x04ZAdd\x12\x1a.immudb.schema.ZAddRequest\x1a\x17.immudb.schema.TxHeader\x12S\n\x0eVerifiableZAdd\x12$.immudb.schema.VerifiableZAddRequest\x1a\x1b.immudb.schema.VerifiableTx\x12=\n\x05ZScan\x12\x1b.immudb.schema.ZScanRequest\x1a\x17.immudb.schema.ZEntries\x12\x41\n\x0e\x43reateDatabase\x12\x17.immudb.schema.Database\x1a\x16.google.protobuf.Empty\x12M\n\x12\x43reateDatabaseWith\x12\x1f.immudb.schema.DatabaseSettings\x1a\x16.google.protobuf.Empty\x12K\n\x0c\x44\x61tabaseList\x12\x16.google.protobuf.Empty\x1a#.immudb.schema.DatabaseListResponse\x12G\n\x0bUseDatabase\x12\x17.immudb.schema.Database\x1a\x1f.immudb.schema.UseDatabaseReply\x12I\n\x0eUpdateDatabase\x12\x1f.immudb.schema.DatabaseSettings\x1a\x16.google.protobuf.Empty\x12>\n\x0c\x43ompactIndex\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\x12R\n\x10\x43hangePermission\x12&.immudb.schema.ChangePermissionRequest\x1a\x16.google.protobuf.Empty\x12L\n\rSetActiveUser\x12#.immudb.schema.SetActiveUserRequest\x1a\x16.google.protobuf.Empty\x12@\n\tstreamGet\x12\x19.immudb.schema.KeyRequest\x1a\x14.immudb.schema.Chunk\"\x00\x30\x01\x12>\n\tstreamSet\x12\x14.immudb.schema.Chunk\x1a\x17.immudb.schema.TxHeader\"\x00(\x01\x12T\n\x13streamVerifiableGet\x12#.immudb.schema.VerifiableGetRequest\x1a\x14.immudb.schema.Chunk\"\x00\x30\x01\x12L\n\x13streamVerifiableSet\x12\x14.immudb.schema.Chunk\x1a\x1b.immudb.schema.VerifiableTx\"\x00(\x01\x12\x42\n\nstreamScan\x12\x1a.immudb.schema.ScanRequest\x1a\x14.immudb.schema.Chunk\"\x00\x30\x01\x12\x44\n\x0bstreamZScan\x12\x1b.immudb.schema.ZScanRequest\x1a\x14.immudb.schema.Chunk\"\x00\x30\x01\x12H\n\rstreamHistory\x12\x1d.immudb.schema.HistoryRequest\x1a\x14.immudb.schema.Chunk\"\x00\x30\x01\x12\x42\n\rstreamExecAll\x12\x14.immudb.schema.Chunk\x1a\x17.immudb.schema.TxHeader\"\x00(\x01\x12>\n\x08\x65xportTx\x12\x18.immudb.schema.TxRequest\x1a\x14.immudb.schema.Chunk\"\x00\x30\x01\x12@\n\x0breplicateTx\x12\x14.immudb.schema.Chunk\x1a\x17.immudb.schema.TxHeader\"\x00(\x01\x12\x46\n\x07SQLExec\x12\x1d.immudb.schema.SQLExecRequest\x1a\x1c.immudb.schema.SQLExecResult\x12I\n\x08SQLQuery\x12\x1e.immudb.schema.SQLQueryRequest\x1a\x1d.immudb.schema.SQLQueryResult\x12\x43\n\nListTables\x12\x16.google.protobuf.Empty\x1a\x1d.immudb.schema.SQLQueryResult\x12\x44\n\rDescribeTable\x12\x14.immudb.schema.Table\x1a\x1d.immudb.schema.SQLQueryResult\x12]\n\x10VerifiableSQLGet\x12&.immudb.schema.VerifiableSQLGetRequest\x1a!.immudb.schema.VerifiableSQLEntryB-Z+github.com/codenotary/immudb/pkg/api/schemab\x06proto3')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cschema.proto\x12\rimmudb.schema\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1cgoogle/protobuf/struct.proto\"\x12\n\x03Key\x12\x0b\n\x03key\x18\x01 \x01(\x0c\"2\n\nPermission\x12\x10\n\x08\x64\x61tabase\x18\x01 \x01(\t\x12\x12\n\npermission\x18\x02 \x01(\r\"z\n\x04User\x12\x0c\n\x04user\x18\x01 \x01(\x0c\x12.\n\x0bpermissions\x18\x03 \x03(\x0b\x32\x19.immudb.schema.Permission\x12\x11\n\tcreatedby\x18\x04 \x01(\t\x12\x11\n\tcreatedat\x18\x05 \x01(\t\x12\x0e\n\x06\x61\x63tive\x18\x06 \x01(\x08\".\n\x08UserList\x12\"\n\x05users\x18\x01 \x03(\x0b\x32\x13.immudb.schema.User\"Y\n\x11\x43reateUserRequest\x12\x0c\n\x04user\x18\x01 \x01(\x0c\x12\x10\n\x08password\x18\x02 \x01(\x0c\x12\x12\n\npermission\x18\x03 \x01(\r\x12\x10\n\x08\x64\x61tabase\x18\x04 \x01(\t\"\x1b\n\x0bUserRequest\x12\x0c\n\x04user\x18\x01 \x01(\x0c\"O\n\x15\x43hangePasswordRequest\x12\x0c\n\x04user\x18\x01 \x01(\x0c\x12\x13\n\x0boldPassword\x18\x02 \x01(\x0c\x12\x13\n\x0bnewPassword\x18\x03 \x01(\x0c\".\n\x0cLoginRequest\x12\x0c\n\x04user\x18\x01 \x01(\x0c\x12\x10\n\x08password\x18\x02 \x01(\x0c\"/\n\rLoginResponse\x12\r\n\x05token\x18\x01 \x01(\t\x12\x0f\n\x07warning\x18\x02 \x01(\x0c\"\x1a\n\nAuthConfig\x12\x0c\n\x04kind\x18\x01 \x01(\r\"\x1d\n\nMTLSConfig\x12\x0f\n\x07\x65nabled\x18\x01 \x01(\x08\"N\n\x12OpenSessionRequest\x12\x10\n\x08username\x18\x01 \x01(\x0c\x12\x10\n\x08password\x18\x02 \x01(\x0c\x12\x14\n\x0c\x64\x61tabaseName\x18\x03 \x01(\t\"<\n\x13OpenSessionResponse\x12\x11\n\tsessionID\x18\x01 \x01(\t\x12\x12\n\nserverUUID\x18\x02 \x01(\t\"S\n\x08KeyValue\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\r\n\x05value\x18\x02 \x01(\x0c\x12+\n\x08metadata\x18\x03 \x01(\x0b\x32\x19.immudb.schema.KVMetadata\"\x9d\x01\n\x05\x45ntry\x12\n\n\x02tx\x18\x01 \x01(\x04\x12\x0b\n\x03key\x18\x02 \x01(\x0c\x12\r\n\x05value\x18\x03 \x01(\x0c\x12.\n\x0creferencedBy\x18\x04 \x01(\x0b\x32\x18.immudb.schema.Reference\x12+\n\x08metadata\x18\x05 \x01(\x0b\x32\x19.immudb.schema.KVMetadata\x12\x0f\n\x07\x65xpired\x18\x06 \x01(\x08\"_\n\tReference\x12\n\n\x02tx\x18\x01 \x01(\x04\x12\x0b\n\x03key\x18\x02 \x01(\x0c\x12\x0c\n\x04\x61tTx\x18\x03 \x01(\x04\x12+\n\x08metadata\x18\x04 \x01(\x0b\x32\x19.immudb.schema.KVMetadata\"\x94\x01\n\x02Op\x12%\n\x02kv\x18\x01 \x01(\x0b\x32\x17.immudb.schema.KeyValueH\x00\x12*\n\x04zAdd\x18\x02 \x01(\x0b\x32\x1a.immudb.schema.ZAddRequestH\x00\x12.\n\x03ref\x18\x03 \x01(\x0b\x32\x1f.immudb.schema.ReferenceRequestH\x00\x42\x0b\n\toperation\"G\n\x0e\x45xecAllRequest\x12%\n\nOperations\x18\x01 \x03(\x0b\x32\x11.immudb.schema.Op\x12\x0e\n\x06noWait\x18\x02 \x01(\x08\"0\n\x07\x45ntries\x12%\n\x07\x65ntries\x18\x01 \x03(\x0b\x32\x14.immudb.schema.Entry\"d\n\x06ZEntry\x12\x0b\n\x03set\x18\x01 \x01(\x0c\x12\x0b\n\x03key\x18\x02 \x01(\x0c\x12#\n\x05\x65ntry\x18\x03 \x01(\x0b\x32\x14.immudb.schema.Entry\x12\r\n\x05score\x18\x04 \x01(\x01\x12\x0c\n\x04\x61tTx\x18\x05 \x01(\x04\"2\n\x08ZEntries\x12&\n\x07\x65ntries\x18\x01 \x03(\x0b\x32\x15.immudb.schema.ZEntry\"l\n\x0bScanRequest\x12\x0f\n\x07seekKey\x18\x01 \x01(\x0c\x12\x0e\n\x06prefix\x18\x02 \x01(\x0c\x12\x0c\n\x04\x64\x65sc\x18\x03 \x01(\x08\x12\r\n\x05limit\x18\x04 \x01(\x04\x12\x0f\n\x07sinceTx\x18\x05 \x01(\x04\x12\x0e\n\x06noWait\x18\x06 \x01(\x08\"\x1b\n\tKeyPrefix\x12\x0e\n\x06prefix\x18\x01 \x01(\x0c\"\x1b\n\nEntryCount\x12\r\n\x05\x63ount\x18\x01 \x01(\x04\"1\n\tSignature\x12\x11\n\tpublicKey\x18\x01 \x01(\x0c\x12\x11\n\tsignature\x18\x02 \x01(\x0c\"\xaf\x01\n\x08TxHeader\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x0f\n\x07prevAlh\x18\x02 \x01(\x0c\x12\n\n\x02ts\x18\x03 \x01(\x03\x12\x10\n\x08nentries\x18\x04 \x01(\x05\x12\n\n\x02\x65H\x18\x05 \x01(\x0c\x12\x0e\n\x06\x62lTxId\x18\x06 \x01(\x04\x12\x0e\n\x06\x62lRoot\x18\x07 \x01(\x0c\x12\x0f\n\x07version\x18\x08 \x01(\x05\x12+\n\x08metadata\x18\t \x01(\x0b\x32\x19.immudb.schema.TxMetadata\"\x0c\n\nTxMetadata\"D\n\x0bLinearProof\x12\x12\n\nsourceTxId\x18\x01 \x01(\x04\x12\x12\n\nTargetTxId\x18\x02 \x01(\x04\x12\r\n\x05terms\x18\x03 \x03(\x0c\"\x83\x02\n\tDualProof\x12/\n\x0esourceTxHeader\x18\x01 \x01(\x0b\x32\x17.immudb.schema.TxHeader\x12/\n\x0etargetTxHeader\x18\x02 \x01(\x0b\x32\x17.immudb.schema.TxHeader\x12\x16\n\x0einclusionProof\x18\x03 \x03(\x0c\x12\x18\n\x10\x63onsistencyProof\x18\x04 \x03(\x0c\x12\x15\n\rtargetBlTxAlh\x18\x05 \x01(\x0c\x12\x1a\n\x12lastInclusionProof\x18\x06 \x03(\x0c\x12/\n\x0blinearProof\x18\x07 \x01(\x0b\x32\x1a.immudb.schema.LinearProof\"V\n\x02Tx\x12\'\n\x06header\x18\x01 \x01(\x0b\x32\x17.immudb.schema.TxHeader\x12\'\n\x07\x65ntries\x18\x02 \x03(\x0b\x32\x16.immudb.schema.TxEntry\"a\n\x07TxEntry\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\x0e\n\x06hValue\x18\x02 \x01(\x0c\x12\x0c\n\x04vLen\x18\x03 \x01(\x05\x12+\n\x08metadata\x18\x04 \x01(\x0b\x32\x19.immudb.schema.KVMetadata\"b\n\nKVMetadata\x12\x0f\n\x07\x64\x65leted\x18\x01 \x01(\x08\x12-\n\nexpiration\x18\x02 \x01(\x0b\x32\x19.immudb.schema.Expiration\x12\x14\n\x0cnonIndexable\x18\x03 \x01(\x08\"\x1f\n\nExpiration\x12\x11\n\texpiresAt\x18\x01 \x01(\x03\"\x87\x01\n\x0cVerifiableTx\x12\x1d\n\x02tx\x18\x01 \x01(\x0b\x32\x11.immudb.schema.Tx\x12+\n\tdualProof\x18\x02 \x01(\x0b\x32\x18.immudb.schema.DualProof\x12+\n\tsignature\x18\x03 \x01(\x0b\x32\x18.immudb.schema.Signature\"\xa0\x01\n\x0fVerifiableEntry\x12#\n\x05\x65ntry\x18\x01 \x01(\x0b\x32\x14.immudb.schema.Entry\x12\x31\n\x0cverifiableTx\x18\x02 \x01(\x0b\x32\x1b.immudb.schema.VerifiableTx\x12\x35\n\x0einclusionProof\x18\x03 \x01(\x0b\x32\x1d.immudb.schema.InclusionProof\"<\n\x0eInclusionProof\x12\x0c\n\x04leaf\x18\x01 \x01(\x05\x12\r\n\x05width\x18\x02 \x01(\x05\x12\r\n\x05terms\x18\x03 \x03(\x0c\"B\n\nSetRequest\x12$\n\x03KVs\x18\x01 \x03(\x0b\x32\x17.immudb.schema.KeyValue\x12\x0e\n\x06noWait\x18\x02 \x01(\x08\"H\n\nKeyRequest\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\x0c\n\x04\x61tTx\x18\x02 \x01(\x04\x12\x0f\n\x07sinceTx\x18\x03 \x01(\x04\x12\x0e\n\x06noWait\x18\x04 \x01(\x08\"/\n\x0eKeyListRequest\x12\x0c\n\x04keys\x18\x01 \x03(\x0c\x12\x0f\n\x07sinceTx\x18\x02 \x01(\x04\"B\n\x11\x44\x65leteKeysRequest\x12\x0c\n\x04keys\x18\x01 \x03(\x0c\x12\x0f\n\x07sinceTx\x18\x02 \x01(\x04\x12\x0e\n\x06noWait\x18\x03 \x01(\x08\"[\n\x14VerifiableSetRequest\x12-\n\nsetRequest\x18\x01 \x01(\x0b\x32\x19.immudb.schema.SetRequest\x12\x14\n\x0cproveSinceTx\x18\x02 \x01(\x04\"[\n\x14VerifiableGetRequest\x12-\n\nkeyRequest\x18\x01 \x01(\x0b\x32\x19.immudb.schema.KeyRequest\x12\x14\n\x0cproveSinceTx\x18\x02 \x01(\x04\"1\n\x0eHealthResponse\x12\x0e\n\x06status\x18\x01 \x01(\x08\x12\x0f\n\x07version\x18\x02 \x01(\t\"Q\n\x16\x44\x61tabaseHealthResponse\x12\x17\n\x0fpendingRequests\x18\x01 \x01(\r\x12\x1e\n\x16lastRequestCompletedAt\x18\x02 \x01(\x03\"g\n\x0eImmutableState\x12\n\n\x02\x64\x62\x18\x01 \x01(\t\x12\x0c\n\x04txId\x18\x02 \x01(\x04\x12\x0e\n\x06txHash\x18\x03 \x01(\x0c\x12+\n\tsignature\x18\x04 \x01(\x0b\x32\x18.immudb.schema.Signature\"f\n\x10ReferenceRequest\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\x15\n\rreferencedKey\x18\x02 \x01(\x0c\x12\x0c\n\x04\x61tTx\x18\x03 \x01(\x04\x12\x10\n\x08\x62oundRef\x18\x04 \x01(\x08\x12\x0e\n\x06noWait\x18\x05 \x01(\x08\"m\n\x1aVerifiableReferenceRequest\x12\x39\n\x10referenceRequest\x18\x01 \x01(\x0b\x32\x1f.immudb.schema.ReferenceRequest\x12\x14\n\x0cproveSinceTx\x18\x02 \x01(\x04\"f\n\x0bZAddRequest\x12\x0b\n\x03set\x18\x01 \x01(\x0c\x12\r\n\x05score\x18\x02 \x01(\x01\x12\x0b\n\x03key\x18\x03 \x01(\x0c\x12\x0c\n\x04\x61tTx\x18\x04 \x01(\x04\x12\x10\n\x08\x62oundRef\x18\x05 \x01(\x08\x12\x0e\n\x06noWait\x18\x06 \x01(\x08\"\x16\n\x05Score\x12\r\n\x05score\x18\x01 \x01(\x01\"\xf6\x01\n\x0cZScanRequest\x12\x0b\n\x03set\x18\x01 \x01(\x0c\x12\x0f\n\x07seekKey\x18\x02 \x01(\x0c\x12\x11\n\tseekScore\x18\x03 \x01(\x01\x12\x10\n\x08seekAtTx\x18\x04 \x01(\x04\x12\x15\n\rinclusiveSeek\x18\x05 \x01(\x08\x12\r\n\x05limit\x18\x06 \x01(\x04\x12\x0c\n\x04\x64\x65sc\x18\x07 \x01(\x08\x12&\n\x08minScore\x18\x08 \x01(\x0b\x32\x14.immudb.schema.Score\x12&\n\x08maxScore\x18\t \x01(\x0b\x32\x14.immudb.schema.Score\x12\x0f\n\x07sinceTx\x18\n \x01(\x04\x12\x0e\n\x06noWait\x18\x0b \x01(\x08\"[\n\x0eHistoryRequest\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\x0e\n\x06offset\x18\x02 \x01(\x04\x12\r\n\x05limit\x18\x03 \x01(\x05\x12\x0c\n\x04\x64\x65sc\x18\x04 \x01(\x08\x12\x0f\n\x07sinceTx\x18\x05 \x01(\x04\"^\n\x15VerifiableZAddRequest\x12/\n\x0bzAddRequest\x18\x01 \x01(\x0b\x32\x1a.immudb.schema.ZAddRequest\x12\x14\n\x0cproveSinceTx\x18\x02 \x01(\x04\"\x17\n\tTxRequest\x12\n\n\x02tx\x18\x01 \x01(\x04\"7\n\x13VerifiableTxRequest\x12\n\n\x02tx\x18\x01 \x01(\x04\x12\x14\n\x0cproveSinceTx\x18\x02 \x01(\x04\"?\n\rTxScanRequest\x12\x11\n\tinitialTx\x18\x01 \x01(\x04\x12\r\n\x05limit\x18\x02 \x01(\r\x12\x0c\n\x04\x64\x65sc\x18\x03 \x01(\x08\"(\n\x06TxList\x12\x1e\n\x03txs\x18\x01 \x03(\x0b\x32\x11.immudb.schema.Tx\" \n\x08\x44\x61tabase\x12\x14\n\x0c\x64\x61tabaseName\x18\x01 \x01(\t\"\xf4\x03\n\x10\x44\x61tabaseSettings\x12\x14\n\x0c\x64\x61tabaseName\x18\x01 \x01(\t\x12\x0f\n\x07replica\x18\x02 \x01(\x08\x12\x16\n\x0emasterDatabase\x18\x03 \x01(\t\x12\x15\n\rmasterAddress\x18\x04 \x01(\t\x12\x12\n\nmasterPort\x18\x05 \x01(\r\x12\x18\n\x10\x66ollowerUsername\x18\x06 \x01(\t\x12\x18\n\x10\x66ollowerPassword\x18\x07 \x01(\t\x12\x10\n\x08\x66ileSize\x18\x08 \x01(\r\x12\x11\n\tmaxKeyLen\x18\t \x01(\r\x12\x13\n\x0bmaxValueLen\x18\n \x01(\r\x12\x14\n\x0cmaxTxEntries\x18\x0b \x01(\r\x12\x19\n\x11\x65xcludeCommitTime\x18\x0c \x01(\x08\x12\x16\n\x0emaxConcurrency\x18\r \x01(\r\x12\x18\n\x10maxIOConcurrency\x18\x0e \x01(\r\x12\x16\n\x0etxLogCacheSize\x18\x0f \x01(\r\x12\x1a\n\x12vLogMaxOpenedFiles\x18\x10 \x01(\r\x12\x1b\n\x13txLogMaxOpenedFiles\x18\x11 \x01(\r\x12\x1f\n\x17\x63ommitLogMaxOpenedFiles\x18\x12 \x01(\r\x12\x33\n\rindexSettings\x18\x13 \x01(\x0b\x32\x1c.immudb.schema.IndexSettings\"\xfc\x02\n\rIndexSettings\x12\x0e\n\x06synced\x18\x01 \x01(\x08\x12\x16\n\x0e\x66lushThreshold\x18\x02 \x01(\r\x12\x15\n\rsyncThreshold\x18\x03 \x01(\r\x12\x11\n\tcacheSize\x18\x04 \x01(\r\x12\x13\n\x0bmaxNodeSize\x18\x05 \x01(\r\x12\x1a\n\x12maxActiveSnapshots\x18\x06 \x01(\r\x12\x1a\n\x12renewSnapRootAfter\x18\x07 \x01(\x04\x12\x16\n\x0e\x63ompactionThld\x18\x08 \x01(\r\x12\x1d\n\x15\x64\x65layDuringCompaction\x18\t \x01(\r\x12\x1e\n\x16nodesLogMaxOpenedFiles\x18\n \x01(\r\x12 \n\x18historyLogMaxOpenedFiles\x18\x0b \x01(\r\x12\x1f\n\x17\x63ommitLogMaxOpenedFiles\x18\x0c \x01(\r\x12\x17\n\x0f\x66lushBufferSize\x18\r \x01(\r\x12\x19\n\x11\x63leanupPercentage\x18\x0e \x01(\r\">\n\x11\x46lushIndexRequest\x12\x19\n\x11\x63leanupPercentage\x18\x01 \x01(\r\x12\x0e\n\x06synced\x18\x02 \x01(\x08\"\x1a\n\x05Table\x12\x11\n\ttableName\x18\x01 \x01(\t\"h\n\rSQLGetRequest\x12\r\n\x05table\x18\x01 \x01(\t\x12)\n\x08pkValues\x18\x02 \x03(\x0b\x32\x17.immudb.schema.SQLValue\x12\x0c\n\x04\x61tTx\x18\x03 \x01(\x04\x12\x0f\n\x07sinceTx\x18\x04 \x01(\x04\"d\n\x17VerifiableSQLGetRequest\x12\x33\n\rsqlGetRequest\x18\x01 \x01(\x0b\x32\x1c.immudb.schema.SQLGetRequest\x12\x14\n\x0cproveSinceTx\x18\x02 \x01(\x04\"_\n\x08SQLEntry\x12\n\n\x02tx\x18\x01 \x01(\x04\x12\x0b\n\x03key\x18\x02 \x01(\x0c\x12\r\n\x05value\x18\x03 \x01(\x0c\x12+\n\x08metadata\x18\x04 \x01(\x0b\x32\x19.immudb.schema.KVMetadata\"\xdd\x05\n\x12VerifiableSQLEntry\x12)\n\x08sqlEntry\x18\x01 \x01(\x0b\x32\x17.immudb.schema.SQLEntry\x12\x31\n\x0cverifiableTx\x18\x02 \x01(\x0b\x32\x1b.immudb.schema.VerifiableTx\x12\x35\n\x0einclusionProof\x18\x03 \x01(\x0b\x32\x1d.immudb.schema.InclusionProof\x12\x12\n\nDatabaseId\x18\x04 \x01(\r\x12\x0f\n\x07TableId\x18\x05 \x01(\r\x12\r\n\x05PKIDs\x18\x10 \x03(\r\x12I\n\x0c\x43olNamesById\x18\x08 \x03(\x0b\x32\x33.immudb.schema.VerifiableSQLEntry.ColNamesByIdEntry\x12I\n\x0c\x43olIdsByName\x18\t \x03(\x0b\x32\x33.immudb.schema.VerifiableSQLEntry.ColIdsByNameEntry\x12I\n\x0c\x43olTypesById\x18\n \x03(\x0b\x32\x33.immudb.schema.VerifiableSQLEntry.ColTypesByIdEntry\x12\x45\n\nColLenById\x18\x0b \x03(\x0b\x32\x31.immudb.schema.VerifiableSQLEntry.ColLenByIdEntry\x1a\x33\n\x11\x43olNamesByIdEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x33\n\x11\x43olIdsByNameEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\r:\x02\x38\x01\x1a\x33\n\x11\x43olTypesByIdEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x31\n\x0f\x43olLenByIdEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01J\x04\x08\x06\x10\x07\"!\n\x10UseDatabaseReply\x12\r\n\x05token\x18\x01 \x01(\t\"\x82\x01\n\x17\x43hangePermissionRequest\x12/\n\x06\x61\x63tion\x18\x01 \x01(\x0e\x32\x1f.immudb.schema.PermissionAction\x12\x10\n\x08username\x18\x02 \x01(\t\x12\x10\n\x08\x64\x61tabase\x18\x03 \x01(\t\x12\x12\n\npermission\x18\x04 \x01(\r\"8\n\x14SetActiveUserRequest\x12\x0e\n\x06\x61\x63tive\x18\x01 \x01(\x08\x12\x10\n\x08username\x18\x02 \x01(\t\"B\n\x14\x44\x61tabaseListResponse\x12*\n\tdatabases\x18\x01 \x03(\x0b\x32\x17.immudb.schema.Database\"\x18\n\x05\x43hunk\x12\x0f\n\x07\x63ontent\x18\x01 \x01(\x0c\"9\n\x12UseSnapshotRequest\x12\x0f\n\x07sinceTx\x18\x01 \x01(\x04\x12\x12\n\nasBeforeTx\x18\x02 \x01(\x04\"X\n\x0eSQLExecRequest\x12\x0b\n\x03sql\x18\x01 \x01(\t\x12)\n\x06params\x18\x02 \x03(\x0b\x32\x19.immudb.schema.NamedParam\x12\x0e\n\x06noWait\x18\x03 \x01(\x08\"`\n\x0fSQLQueryRequest\x12\x0b\n\x03sql\x18\x01 \x01(\t\x12)\n\x06params\x18\x02 \x03(\x0b\x32\x19.immudb.schema.NamedParam\x12\x15\n\rreuseSnapshot\x18\x03 \x01(\x08\"B\n\nNamedParam\x12\x0c\n\x04name\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.immudb.schema.SQLValue\"N\n\rSQLExecResult\x12*\n\x03txs\x18\x05 \x03(\x0b\x32\x1d.immudb.schema.CommittedSQLTx\x12\x11\n\tongoingTx\x18\x06 \x01(\x08\"\x8d\x03\n\x0e\x43ommittedSQLTx\x12\'\n\x06header\x18\x01 \x01(\x0b\x32\x17.immudb.schema.TxHeader\x12\x13\n\x0bupdatedRows\x18\x02 \x01(\r\x12K\n\x0flastInsertedPKs\x18\x03 \x03(\x0b\x32\x32.immudb.schema.CommittedSQLTx.LastInsertedPKsEntry\x12M\n\x10\x66irstInsertedPKs\x18\x04 \x03(\x0b\x32\x33.immudb.schema.CommittedSQLTx.FirstInsertedPKsEntry\x1aO\n\x14LastInsertedPKsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.immudb.schema.SQLValue:\x02\x38\x01\x1aP\n\x15\x46irstInsertedPKsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.immudb.schema.SQLValue:\x02\x38\x01\"Z\n\x0eSQLQueryResult\x12&\n\x07\x63olumns\x18\x02 \x03(\x0b\x32\x15.immudb.schema.Column\x12 \n\x04rows\x18\x01 \x03(\x0b\x32\x12.immudb.schema.Row\"$\n\x06\x43olumn\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04type\x18\x02 \x01(\t\"?\n\x03Row\x12\x0f\n\x07\x63olumns\x18\x01 \x03(\t\x12\'\n\x06values\x18\x02 \x03(\x0b\x32\x17.immudb.schema.SQLValue\"\x82\x01\n\x08SQLValue\x12*\n\x04null\x18\x01 \x01(\x0e\x32\x1a.google.protobuf.NullValueH\x00\x12\x0b\n\x01n\x18\x02 \x01(\x03H\x00\x12\x0b\n\x01s\x18\x03 \x01(\tH\x00\x12\x0b\n\x01\x62\x18\x04 \x01(\x08H\x00\x12\x0c\n\x02\x62s\x18\x05 \x01(\x0cH\x00\x12\x0c\n\x02ts\x18\x06 \x01(\x03H\x00\x42\x07\n\x05value\"3\n\x0cNewTxRequest\x12#\n\x04mode\x18\x01 \x01(\x0e\x32\x15.immudb.schema.TxMode\"&\n\rNewTxResponse\x12\x15\n\rtransactionID\x18\x01 \x01(\t\"(\n\tErrorInfo\x12\x0c\n\x04\x63ode\x18\x01 \x01(\t\x12\r\n\x05\x63\x61use\x18\x02 \x01(\t\"\x1a\n\tDebugInfo\x12\r\n\x05stack\x18\x01 \x01(\t\" \n\tRetryInfo\x12\x13\n\x0bretry_delay\x18\x01 \x01(\x05*)\n\x10PermissionAction\x12\t\n\x05GRANT\x10\x00\x12\n\n\x06REVOKE\x10\x01*4\n\x06TxMode\x12\x0c\n\x08ReadOnly\x10\x00\x12\r\n\tWriteOnly\x10\x01\x12\r\n\tReadWrite\x10\x02\x32\xcf\"\n\x0bImmuService\x12<\n\tListUsers\x12\x16.google.protobuf.Empty\x1a\x17.immudb.schema.UserList\x12\x46\n\nCreateUser\x12 .immudb.schema.CreateUserRequest\x1a\x16.google.protobuf.Empty\x12N\n\x0e\x43hangePassword\x12$.immudb.schema.ChangePasswordRequest\x1a\x16.google.protobuf.Empty\x12\x45\n\x10UpdateAuthConfig\x12\x19.immudb.schema.AuthConfig\x1a\x16.google.protobuf.Empty\x12\x45\n\x10UpdateMTLSConfig\x12\x19.immudb.schema.MTLSConfig\x1a\x16.google.protobuf.Empty\x12V\n\x0bOpenSession\x12!.immudb.schema.OpenSessionRequest\x1a\".immudb.schema.OpenSessionResponse\"\x00\x12@\n\x0c\x43loseSession\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\"\x00\x12=\n\tKeepAlive\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\"\x00\x12\x44\n\x05NewTx\x12\x1b.immudb.schema.NewTxRequest\x1a\x1c.immudb.schema.NewTxResponse\"\x00\x12\x41\n\x06\x43ommit\x12\x16.google.protobuf.Empty\x1a\x1d.immudb.schema.CommittedSQLTx\"\x00\x12<\n\x08Rollback\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\"\x00\x12\x44\n\tTxSQLExec\x12\x1d.immudb.schema.SQLExecRequest\x1a\x16.google.protobuf.Empty\"\x00\x12M\n\nTxSQLQuery\x12\x1e.immudb.schema.SQLQueryRequest\x1a\x1d.immudb.schema.SQLQueryResult\"\x00\x12\x42\n\x05Login\x12\x1b.immudb.schema.LoginRequest\x1a\x1c.immudb.schema.LoginResponse\x12\x38\n\x06Logout\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\x12\x39\n\x03Set\x12\x19.immudb.schema.SetRequest\x1a\x17.immudb.schema.TxHeader\x12Q\n\rVerifiableSet\x12#.immudb.schema.VerifiableSetRequest\x1a\x1b.immudb.schema.VerifiableTx\x12\x36\n\x03Get\x12\x19.immudb.schema.KeyRequest\x1a\x14.immudb.schema.Entry\x12T\n\rVerifiableGet\x12#.immudb.schema.VerifiableGetRequest\x1a\x1e.immudb.schema.VerifiableEntry\x12\x43\n\x06\x44\x65lete\x12 .immudb.schema.DeleteKeysRequest\x1a\x17.immudb.schema.TxHeader\x12?\n\x06GetAll\x12\x1d.immudb.schema.KeyListRequest\x1a\x16.immudb.schema.Entries\x12\x41\n\x07\x45xecAll\x12\x1d.immudb.schema.ExecAllRequest\x1a\x17.immudb.schema.TxHeader\x12:\n\x04Scan\x12\x1a.immudb.schema.ScanRequest\x1a\x16.immudb.schema.Entries\x12<\n\x05\x43ount\x12\x18.immudb.schema.KeyPrefix\x1a\x19.immudb.schema.EntryCount\x12=\n\x08\x43ountAll\x12\x16.google.protobuf.Empty\x1a\x19.immudb.schema.EntryCount\x12\x35\n\x06TxById\x12\x18.immudb.schema.TxRequest\x1a\x11.immudb.schema.Tx\x12S\n\x10VerifiableTxById\x12\".immudb.schema.VerifiableTxRequest\x1a\x1b.immudb.schema.VerifiableTx\x12=\n\x06TxScan\x12\x1c.immudb.schema.TxScanRequest\x1a\x15.immudb.schema.TxList\x12@\n\x07History\x12\x1d.immudb.schema.HistoryRequest\x1a\x16.immudb.schema.Entries\x12?\n\x06Health\x12\x16.google.protobuf.Empty\x1a\x1d.immudb.schema.HealthResponse\x12O\n\x0e\x44\x61tabaseHealth\x12\x16.google.protobuf.Empty\x1a%.immudb.schema.DatabaseHealthResponse\x12\x45\n\x0c\x43urrentState\x12\x16.google.protobuf.Empty\x1a\x1d.immudb.schema.ImmutableState\x12H\n\x0cSetReference\x12\x1f.immudb.schema.ReferenceRequest\x1a\x17.immudb.schema.TxHeader\x12`\n\x16VerifiableSetReference\x12).immudb.schema.VerifiableReferenceRequest\x1a\x1b.immudb.schema.VerifiableTx\x12;\n\x04ZAdd\x12\x1a.immudb.schema.ZAddRequest\x1a\x17.immudb.schema.TxHeader\x12S\n\x0eVerifiableZAdd\x12$.immudb.schema.VerifiableZAddRequest\x1a\x1b.immudb.schema.VerifiableTx\x12=\n\x05ZScan\x12\x1b.immudb.schema.ZScanRequest\x1a\x17.immudb.schema.ZEntries\x12\x41\n\x0e\x43reateDatabase\x12\x17.immudb.schema.Database\x1a\x16.google.protobuf.Empty\x12M\n\x12\x43reateDatabaseWith\x12\x1f.immudb.schema.DatabaseSettings\x1a\x16.google.protobuf.Empty\x12K\n\x0c\x44\x61tabaseList\x12\x16.google.protobuf.Empty\x1a#.immudb.schema.DatabaseListResponse\x12G\n\x0bUseDatabase\x12\x17.immudb.schema.Database\x1a\x1f.immudb.schema.UseDatabaseReply\x12I\n\x0eUpdateDatabase\x12\x1f.immudb.schema.DatabaseSettings\x1a\x16.google.protobuf.Empty\x12N\n\x13GetDatabaseSettings\x12\x16.google.protobuf.Empty\x1a\x1f.immudb.schema.DatabaseSettings\x12\x46\n\nFlushIndex\x12 .immudb.schema.FlushIndexRequest\x1a\x16.google.protobuf.Empty\x12>\n\x0c\x43ompactIndex\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\x12R\n\x10\x43hangePermission\x12&.immudb.schema.ChangePermissionRequest\x1a\x16.google.protobuf.Empty\x12L\n\rSetActiveUser\x12#.immudb.schema.SetActiveUserRequest\x1a\x16.google.protobuf.Empty\x12@\n\tstreamGet\x12\x19.immudb.schema.KeyRequest\x1a\x14.immudb.schema.Chunk\"\x00\x30\x01\x12>\n\tstreamSet\x12\x14.immudb.schema.Chunk\x1a\x17.immudb.schema.TxHeader\"\x00(\x01\x12T\n\x13streamVerifiableGet\x12#.immudb.schema.VerifiableGetRequest\x1a\x14.immudb.schema.Chunk\"\x00\x30\x01\x12L\n\x13streamVerifiableSet\x12\x14.immudb.schema.Chunk\x1a\x1b.immudb.schema.VerifiableTx\"\x00(\x01\x12\x42\n\nstreamScan\x12\x1a.immudb.schema.ScanRequest\x1a\x14.immudb.schema.Chunk\"\x00\x30\x01\x12\x44\n\x0bstreamZScan\x12\x1b.immudb.schema.ZScanRequest\x1a\x14.immudb.schema.Chunk\"\x00\x30\x01\x12H\n\rstreamHistory\x12\x1d.immudb.schema.HistoryRequest\x1a\x14.immudb.schema.Chunk\"\x00\x30\x01\x12\x42\n\rstreamExecAll\x12\x14.immudb.schema.Chunk\x1a\x17.immudb.schema.TxHeader\"\x00(\x01\x12>\n\x08\x65xportTx\x12\x18.immudb.schema.TxRequest\x1a\x14.immudb.schema.Chunk\"\x00\x30\x01\x12@\n\x0breplicateTx\x12\x14.immudb.schema.Chunk\x1a\x17.immudb.schema.TxHeader\"\x00(\x01\x12\x46\n\x07SQLExec\x12\x1d.immudb.schema.SQLExecRequest\x1a\x1c.immudb.schema.SQLExecResult\x12I\n\x08SQLQuery\x12\x1e.immudb.schema.SQLQueryRequest\x1a\x1d.immudb.schema.SQLQueryResult\x12\x43\n\nListTables\x12\x16.google.protobuf.Empty\x1a\x1d.immudb.schema.SQLQueryResult\x12\x44\n\rDescribeTable\x12\x14.immudb.schema.Table\x1a\x1d.immudb.schema.SQLQueryResult\x12]\n\x10VerifiableSQLGet\x12&.immudb.schema.VerifiableSQLGetRequest\x1a!.immudb.schema.VerifiableSQLEntryB-Z+github.com/codenotary/immudb/pkg/api/schemab\x06proto3')
 
 _PERMISSIONACTION = DESCRIPTOR.enum_types_by_name['PermissionAction']
 PermissionAction = enum_type_wrapper.EnumTypeWrapper(_PERMISSIONACTION)
@@ -73,6 +73,7 @@
 _VERIFIABLESETREQUEST = DESCRIPTOR.message_types_by_name['VerifiableSetRequest']
 _VERIFIABLEGETREQUEST = DESCRIPTOR.message_types_by_name['VerifiableGetRequest']
 _HEALTHRESPONSE = DESCRIPTOR.message_types_by_name['HealthResponse']
+_DATABASEHEALTHRESPONSE = DESCRIPTOR.message_types_by_name['DatabaseHealthResponse']
 _IMMUTABLESTATE = DESCRIPTOR.message_types_by_name['ImmutableState']
 _REFERENCEREQUEST = DESCRIPTOR.message_types_by_name['ReferenceRequest']
 _VERIFIABLEREFERENCEREQUEST = DESCRIPTOR.message_types_by_name['VerifiableReferenceRequest']
@@ -87,6 +88,8 @@
 _TXLIST = DESCRIPTOR.message_types_by_name['TxList']
 _DATABASE = DESCRIPTOR.message_types_by_name['Database']
 _DATABASESETTINGS = DESCRIPTOR.message_types_by_name['DatabaseSettings']
+_INDEXSETTINGS = DESCRIPTOR.message_types_by_name['IndexSettings']
+_FLUSHINDEXREQUEST = DESCRIPTOR.message_types_by_name['FlushIndexRequest']
 _TABLE = DESCRIPTOR.message_types_by_name['Table']
 _SQLGETREQUEST = DESCRIPTOR.message_types_by_name['SQLGetRequest']
 _VERIFIABLESQLGETREQUEST = DESCRIPTOR.message_types_by_name['VerifiableSQLGetRequest']
@@ -419,6 +422,13 @@
   })
 _sym_db.RegisterMessage(HealthResponse)
 
+DatabaseHealthResponse = _reflection.GeneratedProtocolMessageType('DatabaseHealthResponse', (_message.Message,), {
+  'DESCRIPTOR' : _DATABASEHEALTHRESPONSE,
+  '__module__' : 'schema_pb2'
+  # @@protoc_insertion_point(class_scope:immudb.schema.DatabaseHealthResponse)
+  })
+_sym_db.RegisterMessage(DatabaseHealthResponse)
+
 ImmutableState = _reflection.GeneratedProtocolMessageType('ImmutableState', (_message.Message,), {
   'DESCRIPTOR' : _IMMUTABLESTATE,
   '__module__' : 'schema_pb2'
@@ -517,6 +527,20 @@
   })
 _sym_db.RegisterMessage(DatabaseSettings)
 
+IndexSettings = _reflection.GeneratedProtocolMessageType('IndexSettings', (_message.Message,), {
+  'DESCRIPTOR' : _INDEXSETTINGS,
+  '__module__' : 'schema_pb2'
+  # @@protoc_insertion_point(class_scope:immudb.schema.IndexSettings)
+  })
+_sym_db.RegisterMessage(IndexSettings)
+
+FlushIndexRequest = _reflection.GeneratedProtocolMessageType('FlushIndexRequest', (_message.Message,), {
+  'DESCRIPTOR' : _FLUSHINDEXREQUEST,
+  '__module__' : 'schema_pb2'
+  # @@protoc_insertion_point(class_scope:immudb.schema.FlushIndexRequest)
+  })
+_sym_db.RegisterMessage(FlushIndexRequest)
+
 Table = _reflection.GeneratedProtocolMessageType('Table', (_message.Message,), {
   'DESCRIPTOR' : _TABLE,
   '__module__' : 'schema_pb2'
@@ -757,10 +781,10 @@
   _COMMITTEDSQLTX_LASTINSERTEDPKSENTRY._serialized_options = b'8\001'
   _COMMITTEDSQLTX_FIRSTINSERTEDPKSENTRY._options = None
   _COMMITTEDSQLTX_FIRSTINSERTEDPKSENTRY._serialized_options = b'8\001'
-  _PERMISSIONACTION._serialized_start=7591
-  _PERMISSIONACTION._serialized_end=7632
-  _TXMODE._serialized_start=7634
-  _TXMODE._serialized_end=7686
+  _PERMISSIONACTION._serialized_start=8376
+  _PERMISSIONACTION._serialized_end=8417
+  _TXMODE._serialized_start=8419
+  _TXMODE._serialized_end=8471
   _KEY._serialized_start=90
   _KEY._serialized_end=108
   _PERMISSION._serialized_start=110
@@ -824,119 +848,125 @@
   _TXENTRY._serialized_start=2434
   _TXENTRY._serialized_end=2531
   _KVMETADATA._serialized_start=2533
-  _KVMETADATA._serialized_end=2609
-  _EXPIRATION._serialized_start=2611
-  _EXPIRATION._serialized_end=2642
-  _VERIFIABLETX._serialized_start=2645
-  _VERIFIABLETX._serialized_end=2780
-  _VERIFIABLEENTRY._serialized_start=2783
-  _VERIFIABLEENTRY._serialized_end=2943
-  _INCLUSIONPROOF._serialized_start=2945
-  _INCLUSIONPROOF._serialized_end=3005
-  _SETREQUEST._serialized_start=3007
-  _SETREQUEST._serialized_end=3073
-  _KEYREQUEST._serialized_start=3075
-  _KEYREQUEST._serialized_end=3131
-  _KEYLISTREQUEST._serialized_start=3133
-  _KEYLISTREQUEST._serialized_end=3180
-  _DELETEKEYSREQUEST._serialized_start=3182
-  _DELETEKEYSREQUEST._serialized_end=3248
-  _VERIFIABLESETREQUEST._serialized_start=3250
-  _VERIFIABLESETREQUEST._serialized_end=3341
-  _VERIFIABLEGETREQUEST._serialized_start=3343
-  _VERIFIABLEGETREQUEST._serialized_end=3434
-  _HEALTHRESPONSE._serialized_start=3436
-  _HEALTHRESPONSE._serialized_end=3485
-  _IMMUTABLESTATE._serialized_start=3487
-  _IMMUTABLESTATE._serialized_end=3590
-  _REFERENCEREQUEST._serialized_start=3592
-  _REFERENCEREQUEST._serialized_end=3694
-  _VERIFIABLEREFERENCEREQUEST._serialized_start=3696
-  _VERIFIABLEREFERENCEREQUEST._serialized_end=3805
-  _ZADDREQUEST._serialized_start=3807
-  _ZADDREQUEST._serialized_end=3909
-  _SCORE._serialized_start=3911
-  _SCORE._serialized_end=3933
-  _ZSCANREQUEST._serialized_start=3936
-  _ZSCANREQUEST._serialized_end=4182
-  _HISTORYREQUEST._serialized_start=4184
-  _HISTORYREQUEST._serialized_end=4275
-  _VERIFIABLEZADDREQUEST._serialized_start=4277
-  _VERIFIABLEZADDREQUEST._serialized_end=4371
-  _TXREQUEST._serialized_start=4373
-  _TXREQUEST._serialized_end=4396
-  _VERIFIABLETXREQUEST._serialized_start=4398
-  _VERIFIABLETXREQUEST._serialized_end=4453
-  _TXSCANREQUEST._serialized_start=4455
-  _TXSCANREQUEST._serialized_end=4518
-  _TXLIST._serialized_start=4520
-  _TXLIST._serialized_end=4560
-  _DATABASE._serialized_start=4562
-  _DATABASE._serialized_end=4594
-  _DATABASESETTINGS._serialized_start=4597
-  _DATABASESETTINGS._serialized_end=4880
-  _TABLE._serialized_start=4882
-  _TABLE._serialized_end=4908
-  _SQLGETREQUEST._serialized_start=4910
-  _SQLGETREQUEST._serialized_end=5014
-  _VERIFIABLESQLGETREQUEST._serialized_start=5016
-  _VERIFIABLESQLGETREQUEST._serialized_end=5116
-  _SQLENTRY._serialized_start=5118
-  _SQLENTRY._serialized_end=5213
-  _VERIFIABLESQLENTRY._serialized_start=5216
-  _VERIFIABLESQLENTRY._serialized_end=5949
-  _VERIFIABLESQLENTRY_COLNAMESBYIDENTRY._serialized_start=5735
-  _VERIFIABLESQLENTRY_COLNAMESBYIDENTRY._serialized_end=5786
-  _VERIFIABLESQLENTRY_COLIDSBYNAMEENTRY._serialized_start=5788
-  _VERIFIABLESQLENTRY_COLIDSBYNAMEENTRY._serialized_end=5839
-  _VERIFIABLESQLENTRY_COLTYPESBYIDENTRY._serialized_start=5841
-  _VERIFIABLESQLENTRY_COLTYPESBYIDENTRY._serialized_end=5892
-  _VERIFIABLESQLENTRY_COLLENBYIDENTRY._serialized_start=5894
-  _VERIFIABLESQLENTRY_COLLENBYIDENTRY._serialized_end=5943
-  _USEDATABASEREPLY._serialized_start=5951
-  _USEDATABASEREPLY._serialized_end=5984
-  _CHANGEPERMISSIONREQUEST._serialized_start=5987
-  _CHANGEPERMISSIONREQUEST._serialized_end=6117
-  _SETACTIVEUSERREQUEST._serialized_start=6119
-  _SETACTIVEUSERREQUEST._serialized_end=6175
-  _DATABASELISTRESPONSE._serialized_start=6177
-  _DATABASELISTRESPONSE._serialized_end=6243
-  _CHUNK._serialized_start=6245
-  _CHUNK._serialized_end=6269
-  _USESNAPSHOTREQUEST._serialized_start=6271
-  _USESNAPSHOTREQUEST._serialized_end=6328
-  _SQLEXECREQUEST._serialized_start=6330
-  _SQLEXECREQUEST._serialized_end=6418
-  _SQLQUERYREQUEST._serialized_start=6420
-  _SQLQUERYREQUEST._serialized_end=6516
-  _NAMEDPARAM._serialized_start=6518
-  _NAMEDPARAM._serialized_end=6584
-  _SQLEXECRESULT._serialized_start=6586
-  _SQLEXECRESULT._serialized_end=6664
-  _COMMITTEDSQLTX._serialized_start=6667
-  _COMMITTEDSQLTX._serialized_end=7064
-  _COMMITTEDSQLTX_LASTINSERTEDPKSENTRY._serialized_start=6903
-  _COMMITTEDSQLTX_LASTINSERTEDPKSENTRY._serialized_end=6982
-  _COMMITTEDSQLTX_FIRSTINSERTEDPKSENTRY._serialized_start=6984
-  _COMMITTEDSQLTX_FIRSTINSERTEDPKSENTRY._serialized_end=7064
-  _SQLQUERYRESULT._serialized_start=7066
-  _SQLQUERYRESULT._serialized_end=7156
-  _COLUMN._serialized_start=7158
-  _COLUMN._serialized_end=7194
-  _ROW._serialized_start=7196
-  _ROW._serialized_end=7259
-  _SQLVALUE._serialized_start=7262
-  _SQLVALUE._serialized_end=7392
-  _NEWTXREQUEST._serialized_start=7394
-  _NEWTXREQUEST._serialized_end=7445
-  _NEWTXRESPONSE._serialized_start=7447
-  _NEWTXRESPONSE._serialized_end=7485
-  _ERRORINFO._serialized_start=7487
-  _ERRORINFO._serialized_end=7527
-  _DEBUGINFO._serialized_start=7529
-  _DEBUGINFO._serialized_end=7555
-  _RETRYINFO._serialized_start=7557
-  _RETRYINFO._serialized_end=7589
-  _IMMUSERVICE._serialized_start=7689
-  _IMMUSERVICE._serialized_end=11887
+  _KVMETADATA._serialized_end=2631
+  _EXPIRATION._serialized_start=2633
+  _EXPIRATION._serialized_end=2664
+  _VERIFIABLETX._serialized_start=2667
+  _VERIFIABLETX._serialized_end=2802
+  _VERIFIABLEENTRY._serialized_start=2805
+  _VERIFIABLEENTRY._serialized_end=2965
+  _INCLUSIONPROOF._serialized_start=2967
+  _INCLUSIONPROOF._serialized_end=3027
+  _SETREQUEST._serialized_start=3029
+  _SETREQUEST._serialized_end=3095
+  _KEYREQUEST._serialized_start=3097
+  _KEYREQUEST._serialized_end=3169
+  _KEYLISTREQUEST._serialized_start=3171
+  _KEYLISTREQUEST._serialized_end=3218
+  _DELETEKEYSREQUEST._serialized_start=3220
+  _DELETEKEYSREQUEST._serialized_end=3286
+  _VERIFIABLESETREQUEST._serialized_start=3288
+  _VERIFIABLESETREQUEST._serialized_end=3379
+  _VERIFIABLEGETREQUEST._serialized_start=3381
+  _VERIFIABLEGETREQUEST._serialized_end=3472
+  _HEALTHRESPONSE._serialized_start=3474
+  _HEALTHRESPONSE._serialized_end=3523
+  _DATABASEHEALTHRESPONSE._serialized_start=3525
+  _DATABASEHEALTHRESPONSE._serialized_end=3606
+  _IMMUTABLESTATE._serialized_start=3608
+  _IMMUTABLESTATE._serialized_end=3711
+  _REFERENCEREQUEST._serialized_start=3713
+  _REFERENCEREQUEST._serialized_end=3815
+  _VERIFIABLEREFERENCEREQUEST._serialized_start=3817
+  _VERIFIABLEREFERENCEREQUEST._serialized_end=3926
+  _ZADDREQUEST._serialized_start=3928
+  _ZADDREQUEST._serialized_end=4030
+  _SCORE._serialized_start=4032
+  _SCORE._serialized_end=4054
+  _ZSCANREQUEST._serialized_start=4057
+  _ZSCANREQUEST._serialized_end=4303
+  _HISTORYREQUEST._serialized_start=4305
+  _HISTORYREQUEST._serialized_end=4396
+  _VERIFIABLEZADDREQUEST._serialized_start=4398
+  _VERIFIABLEZADDREQUEST._serialized_end=4492
+  _TXREQUEST._serialized_start=4494
+  _TXREQUEST._serialized_end=4517
+  _VERIFIABLETXREQUEST._serialized_start=4519
+  _VERIFIABLETXREQUEST._serialized_end=4574
+  _TXSCANREQUEST._serialized_start=4576
+  _TXSCANREQUEST._serialized_end=4639
+  _TXLIST._serialized_start=4641
+  _TXLIST._serialized_end=4681
+  _DATABASE._serialized_start=4683
+  _DATABASE._serialized_end=4715
+  _DATABASESETTINGS._serialized_start=4718
+  _DATABASESETTINGS._serialized_end=5218
+  _INDEXSETTINGS._serialized_start=5221
+  _INDEXSETTINGS._serialized_end=5601
+  _FLUSHINDEXREQUEST._serialized_start=5603
+  _FLUSHINDEXREQUEST._serialized_end=5665
+  _TABLE._serialized_start=5667
+  _TABLE._serialized_end=5693
+  _SQLGETREQUEST._serialized_start=5695
+  _SQLGETREQUEST._serialized_end=5799
+  _VERIFIABLESQLGETREQUEST._serialized_start=5801
+  _VERIFIABLESQLGETREQUEST._serialized_end=5901
+  _SQLENTRY._serialized_start=5903
+  _SQLENTRY._serialized_end=5998
+  _VERIFIABLESQLENTRY._serialized_start=6001
+  _VERIFIABLESQLENTRY._serialized_end=6734
+  _VERIFIABLESQLENTRY_COLNAMESBYIDENTRY._serialized_start=6520
+  _VERIFIABLESQLENTRY_COLNAMESBYIDENTRY._serialized_end=6571
+  _VERIFIABLESQLENTRY_COLIDSBYNAMEENTRY._serialized_start=6573
+  _VERIFIABLESQLENTRY_COLIDSBYNAMEENTRY._serialized_end=6624
+  _VERIFIABLESQLENTRY_COLTYPESBYIDENTRY._serialized_start=6626
+  _VERIFIABLESQLENTRY_COLTYPESBYIDENTRY._serialized_end=6677
+  _VERIFIABLESQLENTRY_COLLENBYIDENTRY._serialized_start=6679
+  _VERIFIABLESQLENTRY_COLLENBYIDENTRY._serialized_end=6728
+  _USEDATABASEREPLY._serialized_start=6736
+  _USEDATABASEREPLY._serialized_end=6769
+  _CHANGEPERMISSIONREQUEST._serialized_start=6772
+  _CHANGEPERMISSIONREQUEST._serialized_end=6902
+  _SETACTIVEUSERREQUEST._serialized_start=6904
+  _SETACTIVEUSERREQUEST._serialized_end=6960
+  _DATABASELISTRESPONSE._serialized_start=6962
+  _DATABASELISTRESPONSE._serialized_end=7028
+  _CHUNK._serialized_start=7030
+  _CHUNK._serialized_end=7054
+  _USESNAPSHOTREQUEST._serialized_start=7056
+  _USESNAPSHOTREQUEST._serialized_end=7113
+  _SQLEXECREQUEST._serialized_start=7115
+  _SQLEXECREQUEST._serialized_end=7203
+  _SQLQUERYREQUEST._serialized_start=7205
+  _SQLQUERYREQUEST._serialized_end=7301
+  _NAMEDPARAM._serialized_start=7303
+  _NAMEDPARAM._serialized_end=7369
+  _SQLEXECRESULT._serialized_start=7371
+  _SQLEXECRESULT._serialized_end=7449
+  _COMMITTEDSQLTX._serialized_start=7452
+  _COMMITTEDSQLTX._serialized_end=7849
+  _COMMITTEDSQLTX_LASTINSERTEDPKSENTRY._serialized_start=7688
+  _COMMITTEDSQLTX_LASTINSERTEDPKSENTRY._serialized_end=7767
+  _COMMITTEDSQLTX_FIRSTINSERTEDPKSENTRY._serialized_start=7769
+  _COMMITTEDSQLTX_FIRSTINSERTEDPKSENTRY._serialized_end=7849
+  _SQLQUERYRESULT._serialized_start=7851
+  _SQLQUERYRESULT._serialized_end=7941
+  _COLUMN._serialized_start=7943
+  _COLUMN._serialized_end=7979
+  _ROW._serialized_start=7981
+  _ROW._serialized_end=8044
+  _SQLVALUE._serialized_start=8047
+  _SQLVALUE._serialized_end=8177
+  _NEWTXREQUEST._serialized_start=8179
+  _NEWTXREQUEST._serialized_end=8230
+  _NEWTXRESPONSE._serialized_start=8232
+  _NEWTXRESPONSE._serialized_end=8270
+  _ERRORINFO._serialized_start=8272
+  _ERRORINFO._serialized_end=8312
+  _DEBUGINFO._serialized_start=8314
+  _DEBUGINFO._serialized_end=8340
+  _RETRYINFO._serialized_start=8342
+  _RETRYINFO._serialized_end=8374
+  _IMMUSERVICE._serialized_start=8474
+  _IMMUSERVICE._serialized_end=12905
 # @@protoc_insertion_point(module_scope)
diff --git a/immudb/grpc/schema_pb2_grpc.py b/immudb/grpc/schema_pb2_grpc.py
index 9ac8e77..0dceaa0 100644
--- a/immudb/grpc/schema_pb2_grpc.py
+++ b/immudb/grpc/schema_pb2_grpc.py
@@ -166,6 +166,11 @@ def __init__(self, channel):
                 request_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString,
                 response_deserializer=schema__pb2.HealthResponse.FromString,
                 )
+        self.DatabaseHealth = channel.unary_unary(
+                '/immudb.schema.ImmuService/DatabaseHealth',
+                request_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString,
+                response_deserializer=schema__pb2.DatabaseHealthResponse.FromString,
+                )
         self.CurrentState = channel.unary_unary(
                 '/immudb.schema.ImmuService/CurrentState',
                 request_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString,
@@ -221,6 +226,16 @@ def __init__(self, channel):
                 request_serializer=schema__pb2.DatabaseSettings.SerializeToString,
                 response_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString,
                 )
+        self.GetDatabaseSettings = channel.unary_unary(
+                '/immudb.schema.ImmuService/GetDatabaseSettings',
+                request_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString,
+                response_deserializer=schema__pb2.DatabaseSettings.FromString,
+                )
+        self.FlushIndex = channel.unary_unary(
+                '/immudb.schema.ImmuService/FlushIndex',
+                request_serializer=schema__pb2.FlushIndexRequest.SerializeToString,
+                response_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString,
+                )
         self.CompactIndex = channel.unary_unary(
                 '/immudb.schema.ImmuService/CompactIndex',
                 request_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString,
@@ -501,6 +516,12 @@ def Health(self, request, context):
         context.set_details('Method not implemented!')
         raise NotImplementedError('Method not implemented!')
 
+    def DatabaseHealth(self, request, context):
+        """Missing associated documentation comment in .proto file."""
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
     def CurrentState(self, request, context):
         """Missing associated documentation comment in .proto file."""
         context.set_code(grpc.StatusCode.UNIMPLEMENTED)
@@ -568,6 +589,18 @@ def UpdateDatabase(self, request, context):
         context.set_details('Method not implemented!')
         raise NotImplementedError('Method not implemented!')
 
+    def GetDatabaseSettings(self, request, context):
+        """Missing associated documentation comment in .proto file."""
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+    def FlushIndex(self, request, context):
+        """Missing associated documentation comment in .proto file."""
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
     def CompactIndex(self, request, context):
         """Missing associated documentation comment in .proto file."""
         context.set_code(grpc.StatusCode.UNIMPLEMENTED)
@@ -831,6 +864,11 @@ def add_ImmuServiceServicer_to_server(servicer, server):
                     request_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString,
                     response_serializer=schema__pb2.HealthResponse.SerializeToString,
             ),
+            'DatabaseHealth': grpc.unary_unary_rpc_method_handler(
+                    servicer.DatabaseHealth,
+                    request_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString,
+                    response_serializer=schema__pb2.DatabaseHealthResponse.SerializeToString,
+            ),
             'CurrentState': grpc.unary_unary_rpc_method_handler(
                     servicer.CurrentState,
                     request_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString,
@@ -886,6 +924,16 @@ def add_ImmuServiceServicer_to_server(servicer, server):
                     request_deserializer=schema__pb2.DatabaseSettings.FromString,
                     response_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString,
             ),
+            'GetDatabaseSettings': grpc.unary_unary_rpc_method_handler(
+                    servicer.GetDatabaseSettings,
+                    request_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString,
+                    response_serializer=schema__pb2.DatabaseSettings.SerializeToString,
+            ),
+            'FlushIndex': grpc.unary_unary_rpc_method_handler(
+                    servicer.FlushIndex,
+                    request_deserializer=schema__pb2.FlushIndexRequest.FromString,
+                    response_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString,
+            ),
             'CompactIndex': grpc.unary_unary_rpc_method_handler(
                     servicer.CompactIndex,
                     request_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString,
@@ -1497,6 +1545,23 @@ def Health(request,
             options, channel_credentials,
             insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
 
+    @staticmethod
+    def DatabaseHealth(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/immudb.schema.ImmuService/DatabaseHealth',
+            google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString,
+            schema__pb2.DatabaseHealthResponse.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
     @staticmethod
     def CurrentState(request,
             target,
@@ -1684,6 +1749,40 @@ def UpdateDatabase(request,
             options, channel_credentials,
             insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
 
+    @staticmethod
+    def GetDatabaseSettings(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/immudb.schema.ImmuService/GetDatabaseSettings',
+            google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString,
+            schema__pb2.DatabaseSettings.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def FlushIndex(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/immudb.schema.ImmuService/FlushIndex',
+            schema__pb2.FlushIndexRequest.SerializeToString,
+            google_dot_protobuf_dot_empty__pb2.Empty.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
     @staticmethod
     def CompactIndex(request,
             target,
diff --git a/immudb/handler/deleteKeys.py b/immudb/handler/deleteKeys.py
new file mode 100644
index 0000000..0a91fec
--- /dev/null
+++ b/immudb/handler/deleteKeys.py
@@ -0,0 +1,25 @@
+# Copyright 2021 CodeNotary, Inc. All rights reserved.
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#       http://www.apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from immudb.datatypes import DeleteKeysRequest
+
+from immudb.grpc import schema_pb2_grpc
+
+
+def call(service: schema_pb2_grpc.ImmuServiceStub, req: DeleteKeysRequest):
+    request = schema_pb2_grpc.schema__pb2.DeleteKeysRequest(
+        keys=req.keys,
+        sinceTx=req.sinceTx,
+        noWait=req.noWait
+    )
+    msg = service.Delete(request)
+    return msg
diff --git a/immudb/handler/setValue.py b/immudb/handler/setValue.py
index 74e859c..108d7df 100644
--- a/immudb/handler/setValue.py
+++ b/immudb/handler/setValue.py
@@ -14,11 +14,16 @@
 from immudb.grpc import schema_pb2_grpc
 from immudb.rootService import RootService
 from immudb import datatypes
+from immudb.embedded.store import KVMetadata
+from immudb.typeconv import MetadataToProto
 
 
-def call(service: schema_pb2_grpc.ImmuServiceStub, rs: RootService, key: bytes, value: bytes):
+def call(service: schema_pb2_grpc.ImmuServiceStub, rs: RootService, key: bytes, value: bytes, metadata: KVMetadata = None):
+    schemaMetadata = MetadataToProto(metadata)
+
     request = schema_pb2.SetRequest(
-        KVs=[schema_pb2.KeyValue(key=key, value=value)]
+        KVs=[schema_pb2.KeyValue(key=key, value=value,
+                                 metadata=schemaMetadata)]
     )
     msg = service.Set(request)
     return datatypes.SetResponse(
diff --git a/immudb/handler/verifiedGet.py b/immudb/handler/verifiedGet.py
index 3016257..a9d4a00 100644
--- a/immudb/handler/verifiedGet.py
+++ b/immudb/handler/verifiedGet.py
@@ -23,18 +23,13 @@
 import sys
 
 
-def call(service: schema_pb2_grpc.ImmuServiceStub, rs: RootService, requestkey: bytes, atTx: int = None, verifying_key=None):
+def call(service: schema_pb2_grpc.ImmuServiceStub, rs: RootService, requestkey: bytes, atTx: int = None, verifying_key=None, sinceTx: int = None):
     state = rs.get()
-    if atTx == None:
-        req = schema_pb2.VerifiableGetRequest(
-            keyRequest=schema_pb2.KeyRequest(key=requestkey),
-            proveSinceTx=state.txId
-        )
-    else:
-        req = schema_pb2.VerifiableGetRequest(
-            keyRequest=schema_pb2.KeyRequest(key=requestkey, atTx=atTx),
-            proveSinceTx=state.txId
-        )
+    req = schema_pb2.VerifiableGetRequest(
+        keyRequest=schema_pb2.KeyRequest(
+            key=requestkey, atTx=atTx, sinceTx=sinceTx),
+        proveSinceTx=state.txId
+    )
     ventry = service.VerifiableGet(req)
     entrySpecDigest = store.EntrySpecDigestFor(
         int(ventry.verifiableTx.tx.header.version))
diff --git a/immudb/handler/verifiedSet.py b/immudb/handler/verifiedSet.py
index 9a8daa9..7ac7503 100644
--- a/immudb/handler/verifiedSet.py
+++ b/immudb/handler/verifiedSet.py
@@ -19,14 +19,16 @@
 from immudb.embedded import store
 import immudb.database as database
 import immudb.schema as schema
+from immudb.typeconv import MetadataToProto
 
 #import base64
 
 
-def call(service: schema_pb2_grpc.ImmuServiceStub, rs: RootService, key: bytes, value: bytes, verifying_key=None):
+def call(service: schema_pb2_grpc.ImmuServiceStub, rs: RootService, key: bytes, value: bytes, verifying_key=None, metadata=None):
+    schemaMetadata = MetadataToProto(metadata)
     state = rs.get()
     # print(base64.b64encode(state.SerializeToString()))
-    kv = schema_pb2.KeyValue(key=key, value=value)
+    kv = schema_pb2.KeyValue(key=key, value=value, metadata=schemaMetadata)
     rawRequest = schema_pb2.VerifiableSetRequest(
         setRequest=schema_pb2.SetRequest(KVs=[kv]),
         proveSinceTx=state.txId,
diff --git a/immudb/schema/database_protoconv.py b/immudb/schema/database_protoconv.py
index 6fff29b..bdd93f3 100644
--- a/immudb/schema/database_protoconv.py
+++ b/immudb/schema/database_protoconv.py
@@ -25,6 +25,19 @@
 
 
 def TxFromProto(stx) -> store.Tx():
+    header = store.TxHeader()
+    header.iD = stx.header.id
+    header.ts = stx.header.ts
+    header.blTxID = stx.header.blTxId
+    header.blRoot = DigestFromProto(stx.header.blRoot)
+    header.prevAlh = DigestFromProto(stx.header.prevAlh)
+
+    header.version = int(stx.header.version)
+    header.metadata = TxMetadataFromProto(stx.header.metadata)
+
+    header.nentries = int(stx.header.nentries)
+    header.eh = DigestFromProto(stx.header.eH)
+
     entries = []
     for e in stx.entries:
         entries.append(
@@ -35,15 +48,9 @@ def TxFromProto(stx) -> store.Tx():
                 DigestFromProto(e.hValue),
                 0)
         )
-    tx = store.NewTxWithEntries(entries)
-    hdr = tx.header
-    hdr.iD = stx.header.id
-    hdr.ts = stx.header.ts
-    hdr.prevAlh = DigestFromProto(stx.header.prevAlh)
-    hdr.blTxID = stx.header.blTxId
-    hdr.blRoot = DigestFromProto(stx.header.blRoot)
-    hdr.version = int(stx.header.version)
-    hdr.metadata = TxMetadataFromProto(stx.header.metadata)
+
+    tx = store.NewTxWithEntries(header, entries)
+
     tx.BuildHashTree()
 
     return tx
@@ -58,6 +65,8 @@ def KVMetadataFromProto(md: grpc_KVMetadata) -> store.KVMetadata:
     if md.HasField("expiration"):
         kvmd.ExpiresAt(datetime.utcfromtimestamp(md.expiration.expiresAt))
 
+    kvmd.AsNonIndexable(md.nonIndexable)
+
     return kvmd
 
 
diff --git a/immudb/typeconv.py b/immudb/typeconv.py
index 3375a0c..f2923a4 100644
--- a/immudb/typeconv.py
+++ b/immudb/typeconv.py
@@ -1,6 +1,7 @@
 from immudb.grpc import schema_pb2
 from pprint import pformat
 from datetime import datetime, timezone
+from immudb.embedded.store import KVMetadata
 
 
 def py_to_sqlvalue(value):
@@ -41,3 +42,17 @@ def sqlvalue_to_py(sqlValue):
     else:
         raise TypeError("Type not supported: {}".format(
             sqlValue.WhichOneof("value")))
+
+
+def MetadataToProto(metadata: KVMetadata):
+    schemaMetadata = None
+    if metadata:
+        schemaMetadata = schema_pb2.KVMetadata()
+        if metadata.Deleted():
+            schemaMetadata.deleted = True
+        if metadata.IsExpirable():
+            schemaMetadata.expiration.expiresAt = int(
+                metadata.ExpirationTime().timestamp())
+        if metadata.NonIndexable():
+            schemaMetadata.nonIndexable = True
+    return schemaMetadata
diff --git a/setup.py b/setup.py
index 73e7671..73376e9 100644
--- a/setup.py
+++ b/setup.py
@@ -17,24 +17,24 @@
     long_description = fh.read()
 
 setup(name='immudb-py',
-      version='1.1.0',
+      version='1.2.3',
       license="Apache License Version 2.0",
       description='Python SDK for Immudb',
       long_description=long_description,
       long_description_content_type="text/markdown",
-      author='vChain',
-      url='https://github.com/codenotary/immu-py',
+      author='Codenotary',
+      url='https://github.com/codenotary/immudb-py',
       # download_url='',
       packages=['immudb', 'immudb.database', 'immudb.embedded',
                 'immudb.embedded.ahtree', 'immudb.embedded.htree', 'immudb.embedded.store',
                 'immudb.grpc', 'immudb.handler', 'immudb.schema'],
       keywords=['immudb', 'immutable'],
       install_requires=[
-          'grpcio>=1.26.0',
+          'grpcio>=1.31.0',
           'dataclasses>=0.6',
           'protobuf>=3.13.0',
           'google-api>=0.1.12',
-          'google-api-core>=1.22.0',
+          'google-api-core>=1.22.1',
           'ecdsa>=0.16.1'
       ],
       classifiers=[


Test patch:
diff --git a/tests/immu/test_database.py b/tests/immu/test_database.py
index 28aa951..b84d67d 100644
--- a/tests/immu/test_database.py
+++ b/tests/immu/test_database.py
@@ -11,9 +11,7 @@
 # limitations under the License.
 
 import pytest
-from immudb.client import ImmudbClient
 from random import randint
-import grpc._channel
 import google.protobuf.empty_pb2
 
 
diff --git a/tests/immu/test_delete.py b/tests/immu/test_delete.py
new file mode 100644
index 0000000..cbc4df4
--- /dev/null
+++ b/tests/immu/test_delete.py
@@ -0,0 +1,55 @@
+# Copyright 2022 CodeNotary, Inc. All rights reserved.
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#       http://www.apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import pytest
+from random import randint
+
+from immudb.datatypes import DeleteKeysRequest
+
+from tests.immuTestClient import ImmuTestClient
+import immudb.constants
+import grpc._channel
+
+
+class TestDelete:
+
+    def test_delete(self, wrappedClient: ImmuTestClient):
+
+        if(wrappedClient.serverHigherOrEqualsToVersion("1.2.0")):
+            key = "delete_key_{:04d}".format(randint(0, 10000))
+            value = "delete_value_{:04d}".format(randint(0, 10000))
+
+            resp = wrappedClient.client.set(
+                key.encode('utf8'), value.encode('utf8'))
+            readback = wrappedClient.client.get(key.encode('utf8'))
+            assert value == readback.value.decode('utf8')
+
+            req = DeleteKeysRequest([key.encode('utf8')])
+
+            resp = wrappedClient.client.delete(req)
+            txid = resp.id
+
+            assert resp.nentries == 1
+
+            readback = wrappedClient.client.get(key.encode('utf8'))
+            assert readback == None  # its gone...
+
+            hist = wrappedClient.client.history(key.encode('utf8'), 0, 99,
+                                                immudb.constants.NEWEST_FIRST)
+
+            assert len(hist) == 2  # ...and can be seen in history
+
+            with pytest.raises(grpc._channel._InactiveRpcError):
+                verifiedDeletedReadback = wrappedClient.client.verifiedGetAt(
+                    key=key.encode('utf8'), atTx=txid)
+        else:
+            pytest.skip()
diff --git a/tests/immu/test_execAll.py b/tests/immu/test_execAll.py
index 9fd33b7..fbc3cfa 100644
--- a/tests/immu/test_execAll.py
+++ b/tests/immu/test_execAll.py
@@ -15,7 +15,6 @@
 from immudb.datatypes import KeyValue, ZAddRequest, ReferenceRequest
 from random import randint
 import grpc._channel
-import time
 
 
 class TestExecAll:
diff --git a/tests/immu/test_expireableSet.py b/tests/immu/test_expireableSet.py
new file mode 100644
index 0000000..311142f
--- /dev/null
+++ b/tests/immu/test_expireableSet.py
@@ -0,0 +1,47 @@
+# Copyright 2022 CodeNotary, Inc. All rights reserved.
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#       http://www.apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+import pytest
+from random import randint
+
+from tests.immuTestClient import ImmuTestClient
+import datetime
+import time
+import grpc._channel
+
+
+class TestExpireableSet:
+
+    def test_expireableSet(self, wrappedClient: ImmuTestClient):
+
+        if(wrappedClient.serverHigherOrEqualsToVersion("1.2.1")):
+            key = "expire_key_{:04d}".format(randint(0, 10000))
+            value = "expire_value_{:04d}".format(randint(0, 10000))
+
+            expiresAt = datetime.datetime.now()+datetime.timedelta(seconds=5)
+
+            resp = wrappedClient.client.expireableSet(
+                key.encode('utf8'), value.encode('utf8'), expiresAt)
+            readback = wrappedClient.client.verifiedGet(key.encode('utf8'))
+            assert value == readback.value.decode('utf8')
+
+            time.sleep(6)
+
+            with pytest.raises(grpc._channel._InactiveRpcError):
+                verifiedExpiredReadback = wrappedClient.client.verifiedGet(
+                    key=key.encode('utf8'))
+            with pytest.raises(grpc._channel._InactiveRpcError):
+                expiredReadback = wrappedClient.client.get(
+                    key=key.encode('utf8'))
+        else:
+            pytest.skip()
diff --git a/tests/immu/test_get_set.py b/tests/immu/test_get_set.py
index 16d8362..83ad9a5 100644
--- a/tests/immu/test_get_set.py
+++ b/tests/immu/test_get_set.py
@@ -10,11 +10,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import pytest
 from immudb.client import ImmudbClient
 from random import randint
-import grpc._channel
-import time
 
 
 class TestGetSet:
diff --git a/tests/immu/test_history.py b/tests/immu/test_history.py
index c745d93..ebf55dd 100644
--- a/tests/immu/test_history.py
+++ b/tests/immu/test_history.py
@@ -10,11 +10,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import pytest
 import immudb.client
 import immudb.constants
 from random import randint
-import grpc._channel
 
 
 class TestHistory:
diff --git a/tests/immu/test_kvmetadata.py b/tests/immu/test_kvmetadata.py
new file mode 100644
index 0000000..af52c96
--- /dev/null
+++ b/tests/immu/test_kvmetadata.py
@@ -0,0 +1,47 @@
+# Copyright 2022 CodeNotary, Inc. All rights reserved.
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#       http://www.apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import pytest
+from random import randint
+from tests.immuTestClient import ImmuTestClient
+import datetime
+from immudb.handler import verifiedSet
+from immudb.embedded.store import KVMetadata
+from immudb.exceptions import ErrCorruptedData
+
+
+class TestKVMetadata:
+
+    def test_kvmetadataproof(self, wrappedClient: ImmuTestClient):
+
+        if(wrappedClient.serverHigherOrEqualsToVersion("1.2.2")):
+            key = "metadata_key_{:04d}".format(randint(0, 10000))
+            value = "metadata_value_{:04d}".format(randint(0, 10000))
+
+            expiresAt = datetime.datetime.now()+datetime.timedelta(seconds=5)
+
+            metadata = KVMetadata()
+            metadata.ExpiresAt(expiresAt)
+            metadata.AsNonIndexable(True)
+
+            resp = verifiedSet.call(wrappedClient.client._ImmudbClient__stub,
+                                    wrappedClient.client._ImmudbClient__rs, key.encode("utf8"), value.encode("utf8"), metadata=metadata)
+
+            assert resp.verified == True
+
+            metadata.AsDeleted(True)
+
+            with pytest.raises(ErrCorruptedData):
+                resp = verifiedSet.call(wrappedClient.client._ImmudbClient__stub,
+                                        wrappedClient.client._ImmudbClient__rs, key.encode("utf8"), value.encode("utf8"), metadata=metadata)
+        else:
+            pytest.skip()
diff --git a/tests/immu/test_massive_operation.py b/tests/immu/test_massive_operation.py
index 159d347..c0a8a95 100644
--- a/tests/immu/test_massive_operation.py
+++ b/tests/immu/test_massive_operation.py
@@ -10,11 +10,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import pytest
-from immudb.client import ImmudbClient
 import string
 import random
-import grpc._channel
 import time
 
 
@@ -43,6 +40,6 @@ def test_get_set_massive(self, client):
         for i in resp.keys():
             assert i in xset
             assert xset[i] == resp[i]
-            
+
     def test_compact(self, client):
         client.compactIndex()
diff --git a/tests/immu/test_offline.py b/tests/immu/test_offline.py
index ec59ed2..2a81fc6 100644
--- a/tests/immu/test_offline.py
+++ b/tests/immu/test_offline.py
@@ -10,14 +10,18 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import pytest
 import base64
+from string import printable
 from immudb.embedded import store, htree, ahtree
-from immudb import constants
+from immudb.embedded.store.tx import TxEntryDigest_v1_1
 from immudb.grpc import schema_pb2
 import immudb.database as database
 import immudb.schema as schema
-from immudb.exceptions import ErrCorruptedData
+from immudb.exceptions import ErrCorruptedData, ErrKeyNotFound, ErrMaxWidthExceeded, ErrMetadataUnsupported, ErrReadOnly, ErrIllegalArguments, ErrNonExpirable, ErrUnsupportedTxVersion
+from immudb.embedded.store import KVMetadata, EntrySpecDigestFor, Tx as storeTx, TxHeader as storeTxHeader, TxEntry
+import pytest
+import datetime
+from immudb.printable import printable
 
 v0 = b'CnIIGhIg0IswQi+55M5xLZSEZUNnpSqoU7JSjtSgNZBlyCMK/3IYzfrjgAYgASogsgXOdHznBIOL0fRjDit+QmDn+9M5FZms8jTI5fHfcpIwGTogmXu3vjcP/kHZTXvT0O158Tx9A3ywjmHG0LOPxS5Bk9kSOwoLAHNhbGFjYWR1bGESIMTfI1H+rKu77CCQQ/ktaUmx/krECfmjHSg+Gy3Zc2NvGMyAgICAgICAASAL'
 s1 = b'CglkZWZhdWx0ZGIaIOOwxEKY/BwUmvv0yJlvuSQnrkHkZJuTTKSVmRt4UrhV'
@@ -102,6 +106,11 @@ def test_printable():
     s = repr(txm)
     assert type(s) == str
 
+    q = printable()
+    q.a = [b'1', b'2']
+    dummy = str(q)
+    assert dummy == 'class printable\n\ta:\n\t- [49]\n\t- [50]\n'
+
 
 class FakeProof(object):
     pass
@@ -177,3 +186,70 @@ def test_htree():
     dig = [b'42', b'8853', b'ivoasiuyf', b'a0ds9zcv', b'zotopac']
     h.BuildWith(dig)
     assert h.InclusionProof(1)
+
+    with pytest.raises(ErrMaxWidthExceeded):
+        dig = [b'42', b'8853', b'ivoasiuyf', b'a0ds9zcv', b'42', b'8853',
+               b'ivoasiuyf', b'a0ds9zcv', b'42', b'8853', b'ivoasiuyf', b'a0ds9zcv']
+        h.BuildWith(dig)
+
+    with pytest.raises(ErrIllegalArguments):
+        dig = []
+        h.BuildWith(dig)
+
+    with pytest.raises(ErrIllegalArguments):
+        h.InclusionProof(12)
+
+
+def test_kvmetadata():
+    md = KVMetadata()
+    md.readonly = True
+    with pytest.raises(ErrReadOnly):
+        md.AsDeleted(True)
+    with pytest.raises(ErrReadOnly):
+        md.ExpiresAt(datetime.datetime.now())
+    with pytest.raises(ErrReadOnly):
+        md.AsNonIndexable(True)
+    assert md.NonExpirable() == None
+    with pytest.raises(ErrNonExpirable):
+        dummy = md.ExpirationTime()
+
+
+def test_unknownTxHeaderVersion():
+    with pytest.raises(ErrUnsupportedTxVersion):
+        dummy = EntrySpecDigestFor(-1)
+    with pytest.raises(ErrUnsupportedTxVersion):
+        dummy = EntrySpecDigestFor(2)
+
+
+def test_tx():
+    tx = storeTx()
+    tx.header = storeTxHeader()
+    tx.header.version = 3
+    with pytest.raises(ErrCorruptedData):
+        dummy = tx.TxEntryDigest()
+
+    md = KVMetadata()
+    md.ExpiresAt(datetime.datetime.now())
+    txEntry = TxEntry(b'key', md, 0, b'123', 0)
+
+    tx.entries = [txEntry]
+
+    with pytest.raises(ErrKeyNotFound):
+        dummy = tx.IndexOf(b"asdf")
+
+
+def test_txEntryDigest_v1_1():
+    md = KVMetadata()
+    md.ExpiresAt(datetime.datetime.now())
+    txEntry = TxEntry(b'key', md, 0, b'123', 0)
+
+    with pytest.raises(ErrMetadataUnsupported):
+        q = TxEntryDigest_v1_1(txEntry)
+
+
+def test_KVMetadataFromProto():
+    assert schema.KVMetadataFromProto(None) == None
+
+
+def test_TxMetadataFromProto():
+    assert schema.TxMetadataFromProto(None) == None
diff --git a/tests/immu/test_permission.py b/tests/immu/test_permission.py
index b33347d..50cdada 100644
--- a/tests/immu/test_permission.py
+++ b/tests/immu/test_permission.py
@@ -10,8 +10,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import pytest
-from immudb.client import ImmudbClient
 
 from immudb.constants import PERMISSION_RW, PERMISSION_R
 from immudb.grpc.schema_pb2 import GRANT, REVOKE
diff --git a/tests/immu/test_ref.py b/tests/immu/test_ref.py
index e3ced78..9513a59 100644
--- a/tests/immu/test_ref.py
+++ b/tests/immu/test_ref.py
@@ -10,11 +10,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import pytest
-from immudb.client import ImmudbClient
 import random
 import string
-import grpc._channel
 
 
 def get_random_string(length):
diff --git a/tests/immu/test_scan.py b/tests/immu/test_scan.py
index 0fefa6e..72f2ea8 100644
--- a/tests/immu/test_scan.py
+++ b/tests/immu/test_scan.py
@@ -10,11 +10,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import pytest
-from immudb.client import ImmudbClient
+
 import random
 import string
-import grpc._channel
 
 
 def get_random_string(length):
diff --git a/tests/immu/test_sql_count.py b/tests/immu/test_sql_count.py
index 37c1463..16c2381 100644
--- a/tests/immu/test_sql_count.py
+++ b/tests/immu/test_sql_count.py
@@ -15,32 +15,37 @@
 
 class TestSQLCount:
 
-
     def test_sql_count(self, wrappedClient: ImmuTestClient):
         # 1.2.0 introduces COUNT(*) instead of COUNT()
         queryToCount = "COUNT()"
-        if wrappedClient.amIHigherOrEqualsToVersion("1.2.0"):
+        if wrappedClient.serverHigherOrEqualsToVersion("1.2.0"):
             queryToCount = "COUNT(*)"
 
-        tabname = wrappedClient.createTestTable("id INTEGER AUTO_INCREMENT", "tester VARCHAR[10]", "PRIMARY KEY id")
-        wrappedClient.insertToTable(tabname, ["tester"], ["@test"], {"test": "test"})
-        result = wrappedClient.simpleSelect(tabname, ["tester"], {"testvalue": "test"}, "tester=@testvalue")
+        tabname = wrappedClient.createTestTable(
+            "id INTEGER AUTO_INCREMENT", "tester VARCHAR[10]", "PRIMARY KEY id")
+        wrappedClient.insertToTable(
+            tabname, ["tester"], ["@test"], {"test": "test"})
+        result = wrappedClient.simpleSelect(
+            tabname, ["tester"], {"testvalue": "test"}, "tester=@testvalue")
         assert(len(result) > 0)
         assert(result[0][0] == "test")
 
-        result = wrappedClient.simpleSelect(tabname, [queryToCount], {"testvalue": "test"}, "tester=@testvalue")
+        result = wrappedClient.simpleSelect(
+            tabname, [queryToCount], {"testvalue": "test"}, "tester=@testvalue")
         assert(len(result) > 0)
         assert(result[0][0] == 1)
 
-        wrappedClient.insertToTable(tabname, ["tester"], ["@test"], {"test": "test"})
-        result = wrappedClient.simpleSelect(tabname, [queryToCount], {"testvalue": "test"}, "tester=@testvalue")
+        wrappedClient.insertToTable(
+            tabname, ["tester"], ["@test"], {"test": "test"})
+        result = wrappedClient.simpleSelect(
+            tabname, [queryToCount], {"testvalue": "test"}, "tester=@testvalue")
         assert(len(result) > 0)
         assert(result[0][0] == 2)
 
         for index in range(0, 10):
-            wrappedClient.insertToTable(tabname, ["tester"], ["@test"], {"test": "test"})
-        result = wrappedClient.simpleSelect(tabname, [queryToCount], {"testvalue": "test"}, "tester=@testvalue")
+            wrappedClient.insertToTable(
+                tabname, ["tester"], ["@test"], {"test": "test"})
+        result = wrappedClient.simpleSelect(
+            tabname, [queryToCount], {"testvalue": "test"}, "tester=@testvalue")
         assert(len(result) > 0)
         assert(result[0][0] == 12)
-
-
diff --git a/tests/immu/test_sql_timestamp.py b/tests/immu/test_sql_timestamp.py
index 5376e0e..f7e57f8 100644
--- a/tests/immu/test_sql_timestamp.py
+++ b/tests/immu/test_sql_timestamp.py
@@ -20,16 +20,20 @@
 class TestSqlTimestamp:
 
     def test_exec_query_timestamp(self, wrappedClient: ImmuTestClient):
-        if(wrappedClient.amIHigherOrEqualsToVersion("1.2.0")):
-            tabname = wrappedClient.createTestTable("id INTEGER", "ts TIMESTAMP", "PRIMARY KEY id")
-            wrappedClient.insertToTable(tabname, ["id", "ts"], ["@id", "NOW()"], {'id': 1})
-            
+        if(wrappedClient.serverHigherOrEqualsToVersion("1.2.0")):
+            tabname = wrappedClient.createTestTable(
+                "id INTEGER", "ts TIMESTAMP", "PRIMARY KEY id")
+            wrappedClient.insertToTable(tabname, ["id", "ts"], [
+                                        "@id", "NOW()"], {'id': 1})
+
             tstest = pytz.timezone(
                 "US/Eastern").localize(datetime(2022, 5, 6, 1, 2, 3, 123456))
 
-            wrappedClient.insertToTable(tabname, ["id", "ts"], ["@id", "@ts"], {'id': 2, 'ts': tstest})
+            wrappedClient.insertToTable(tabname, ["id", "ts"], [
+                                        "@id", "@ts"], {'id': 2, 'ts': tstest})
 
-            result = wrappedClient.simpleSelect(tabname, ["id", "ts"], {'id': 1}, "id=@id")
+            result = wrappedClient.simpleSelect(
+                tabname, ["id", "ts"], {'id': 1}, "id=@id")
             assert(len(result) > 0)
             assert(result[0][0] == 1)
             # calculate timediff of now.
@@ -37,9 +41,11 @@ def test_exec_query_timestamp(self, wrappedClient: ImmuTestClient):
                 datetime.utcnow())-result[0][1]).total_seconds()
             assert(abs(td) < 2)
 
-            result = wrappedClient.simpleSelect(tabname, ["id", "ts"], {'id': 2}, "id=@id")
+            result = wrappedClient.simpleSelect(
+                tabname, ["id", "ts"], {'id': 2}, "id=@id")
 
             assert(len(result) > 0)
             assert(result[0] == (2, tstest))
         else:
-            print("Feature wasn't supported before 1.2.0")
+            pytest.skip()
+            #print("Feature wasn't supported before 1.2.0")
diff --git a/tests/immu/test_sql_transaction.py b/tests/immu/test_sql_transaction.py
index 8c95a87..b470215 100644
--- a/tests/immu/test_sql_transaction.py
+++ b/tests/immu/test_sql_transaction.py
@@ -11,47 +11,51 @@
 # limitations under the License.
 
 from tests.immuTestClient import ImmuTestClient
+
+
 class TestSQLTransaction:
     def test_sql_simple_transaction_multiline(self, wrappedClient: ImmuTestClient):
         # BEFORE 1.2.0 we can't pass ; at the end of BEGIN TRANSACTION
         countQuery = "COUNT(*)"
-        if(not wrappedClient.amIHigherOrEqualsToVersion("1.2.0")):
+        if(not wrappedClient.serverHigherOrEqualsToVersion("1.2.0")):
             wrappedClient.transactionStart = "BEGIN TRANSACTION"
             countQuery = "COUNT()"
 
-        tabname = wrappedClient.createTestTable("id INTEGER AUTO_INCREMENT", "tester VARCHAR[10]", "PRIMARY KEY id")
+        tabname = wrappedClient.createTestTable(
+            "id INTEGER AUTO_INCREMENT", "tester VARCHAR[10]", "PRIMARY KEY id")
         params = dict()
         queries = []
         for index in range(0, 10):
-            paramName = "tester{index}".format(index = index)
+            paramName = "tester{index}".format(index=index)
             params[paramName] = str(index)
-            queries.append(wrappedClient.prepareInsertQuery(tabname, ["tester"], ["@" + paramName]))
+            queries.append(wrappedClient.prepareInsertQuery(
+                tabname, ["tester"], ["@" + paramName]))
 
         wrappedClient.executeWithTransaction(params, queries)
 
         counted = wrappedClient.simpleSelect(tabname, [countQuery], dict())
         assert(len(counted) > 0)
         assert(counted[0][0] == 10)
-    
+
     def test_sql_simple_transaction_flat(self, wrappedClient: ImmuTestClient):
         # BEFORE 1.2.0 we can't pass ; at the end of BEGIN TRANSACTION
         countQuery = "COUNT(*)"
-        if(not wrappedClient.amIHigherOrEqualsToVersion("1.2.0")):
+        if(not wrappedClient.serverHigherOrEqualsToVersion("1.2.0")):
             wrappedClient.transactionStart = "BEGIN TRANSACTION"
             countQuery = "COUNT()"
 
-        tabname = wrappedClient.createTestTable("id INTEGER AUTO_INCREMENT", "tester VARCHAR[10]", "PRIMARY KEY id")
+        tabname = wrappedClient.createTestTable(
+            "id INTEGER AUTO_INCREMENT", "tester VARCHAR[10]", "PRIMARY KEY id")
         params = dict()
         queries = []
         for index in range(0, 10):
-            paramName = "tester{index}".format(index = index)
+            paramName = "tester{index}".format(index=index)
             params[paramName] = str(index)
-            queries.append(wrappedClient.prepareInsertQuery(tabname, ["tester"], ["@" + paramName]))
+            queries.append(wrappedClient.prepareInsertQuery(
+                tabname, ["tester"], ["@" + paramName]))
 
-        wrappedClient.executeWithTransaction(params, queries, separator = " ")
+        wrappedClient.executeWithTransaction(params, queries, separator=" ")
 
         counted = wrappedClient.simpleSelect(tabname, [countQuery], dict())
         assert(len(counted) > 0)
         assert(counted[0][0] == 10)
-
-
diff --git a/tests/immu/test_user_operations.py b/tests/immu/test_user_operations.py
index 31a80fc..72125f6 100644
--- a/tests/immu/test_user_operations.py
+++ b/tests/immu/test_user_operations.py
@@ -1,5 +1,16 @@
-import pytest
-from immudb.client import ImmudbClient
+# Copyright 2022 CodeNotary, Inc. All rights reserved.
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#       http://www.apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
 import immudb.constants
 from immudb.grpc import schema_pb2
 import string
diff --git a/tests/immu/test_verified_get_set.py b/tests/immu/test_verified_get_set.py
new file mode 100644
index 0000000..3d25adb
--- /dev/null
+++ b/tests/immu/test_verified_get_set.py
@@ -0,0 +1,56 @@
+# Copyright 2021 CodeNotary, Inc. All rights reserved.
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#       http://www.apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from immudb.client import ImmudbClient
+from random import randint
+import pytest
+import grpc._channel
+
+
+class TestVerifiedGetSet:
+
+    def test_verified(self, client: ImmudbClient):
+
+        key1 = "verified_key_{:04d}".format(randint(0, 10000))
+        value1 = "verified_value_{:04d}".format(randint(0, 10000))
+
+        resp = client.verifiedSet(
+            key1.encode('utf8'), value1.encode('utf8'))
+
+        readback1 = client.verifiedGet(key1.encode('utf8'))
+        assert value1 == readback1.value.decode('utf8')
+
+        tx1id = readback1.id
+
+        key2 = "verified_key_{:04d}".format(randint(0, 10000))
+        value2 = "verified_value_{:04d}".format(randint(0, 10000))
+
+        resp = client.verifiedSet(
+            key2.encode('utf8'), value2.encode('utf8'))
+
+        readback2 = client.verifiedGet(key2.encode('utf8'))
+        assert value2 == readback2.value.decode('utf8')
+
+        tx2id = readback2.id
+
+        readback3 = client.verifiedGetAt(key1.encode('utf8'), atTx=tx1id)
+        assert value1 == readback3.value.decode('utf8')
+
+        with pytest.raises(grpc._channel._InactiveRpcError):
+            readback4 = client.verifiedGetAt(key2.encode('utf8'), atTx=tx1id)
+
+        readback5 = client.verifiedGetSince(key1.encode('utf8'), sinceTx=tx1id)
+        assert value1 == readback5.value.decode('utf8')
+
+        with pytest.raises(grpc._channel._InactiveRpcError):
+            readback6 = client.verifiedGetSince(
+                key1.encode('utf8'), sinceTx=tx2id)
diff --git a/tests/immuTestClient.py b/tests/immuTestClient.py
index 0d5db0c..a2e2519 100644
--- a/tests/immuTestClient.py
+++ b/tests/immuTestClient.py
@@ -4,27 +4,27 @@
 import uuid
 from typing import List
 
+
 class ImmuTestClient:
     def __init__(self, client: ImmudbClient):
         self.client = client
         self.transactionStart = "BEGIN TRANSACTION;"
         self.transactionEnd = "COMMIT;"
 
-    def amIHigherOrEqualsToVersion(self, version: str):
+    def serverHigherOrEqualsToVersion(self, version: str):
         health = self.client.health()
         return self.compare_version(health.version, version) > -1
 
-    def executeWithTransaction(self, concatenatedParams: dict, queries: List[str], separator = "\n"):
+    def executeWithTransaction(self, concatenatedParams: dict, queries: List[str], separator="\n"):
         toExecute = [self.transactionStart]
         toExecute.extend(queries)
         toExecute.append(self.transactionEnd)
         multiLineQuery = separator.join(toExecute)
         resp = self.client.sqlExec(multiLineQuery, concatenatedParams)
         assert((len(resp.txs) > 0 and not resp.ongoingTx and not resp.UnknownFields())
-                   or len(resp.UnknownFields()) > 0)
+               or len(resp.UnknownFields()) > 0)
         return resp
 
-
     def _generateTableName(self):
         return ("T" + str(uuid.uuid4()).replace("-", "")).lower()
 
@@ -33,47 +33,48 @@ def createTestTable(self, *fields: List[str]):
         tabname = self._generateTableName()
         fieldsJoined = ",".join(fields)
         resp = self.client.sqlExec(
-            "CREATE TABLE {table} ({fieldsJoined});".format(table = tabname, fieldsJoined = fieldsJoined)
+            "CREATE TABLE {table} ({fieldsJoined});".format(
+                table=tabname, fieldsJoined=fieldsJoined)
         )
         assert((len(resp.txs) > 0 and not resp.ongoingTx and not resp.UnknownFields())
-                   or len(resp.UnknownFields()) > 0)
+               or len(resp.UnknownFields()) > 0)
 
         resp = self.client.listTables()
         assert tabname in resp
         return tabname
 
-
     def prepareInsertQuery(self, table: str, fields: List[str], values: List):
         fieldsJoined = ",".join(fields)
         paramsJoined = ",".join(values)
-        return "INSERT INTO {table} ({fieldsJoined}) VALUES ({paramsJoined});".format(table=table, fieldsJoined = fieldsJoined, paramsJoined = paramsJoined)
+        return "INSERT INTO {table} ({fieldsJoined}) VALUES ({paramsJoined});".format(table=table, fieldsJoined=fieldsJoined, paramsJoined=paramsJoined)
 
     def prepareSelectQuery(self, fromWhat: str, whatToSelect: List[str], conditions: List[str]):
         fieldsJoined = ",".join(whatToSelect)
         conditionsJoined = ",".join(conditions)
 
-        constructed = "SELECT {fieldsJoined} FROM {table}".format(table=fromWhat, fieldsJoined = fieldsJoined)
+        constructed = "SELECT {fieldsJoined} FROM {table}".format(
+            table=fromWhat, fieldsJoined=fieldsJoined)
         if(len(conditions) > 0):
-             constructed = constructed + " WHERE " + conditionsJoined
+            constructed = constructed + " WHERE " + conditionsJoined
         constructed = constructed + ";"
 
         return constructed
 
-    # @TODO define possible types of values 
+    # @TODO define possible types of values
     def insertToTable(self, table: str, fields: List[str], values: List, params: dict):
         preparedQuery = self.prepareInsertQuery(table, fields, values)
         resp = self.client.sqlExec(preparedQuery, params)
         assert((len(resp.txs) > 0 and not resp.ongoingTx and not resp.UnknownFields())
-                   or len(resp.UnknownFields()) > 0)
+               or len(resp.UnknownFields()) > 0)
         return resp
 
     def simpleSelect(self, fromWhat: str, whatToSelect: List[str], params: dict, *conditions: List[str]):
-        preparedQuery = self.prepareSelectQuery(fromWhat, whatToSelect, conditions)
+        preparedQuery = self.prepareSelectQuery(
+            fromWhat, whatToSelect, conditions)
         result = self.client.sqlQuery(preparedQuery, params)
         return result
 
-    
-    def compare_version(self, a: str , b: str):
+    def compare_version(self, a: str, b: str):
         aNumber = a.split("-")
         bNumber = b.split("-")
         (aMajor, aMinor, aRev) = aNumber[0].split(".")
@@ -83,4 +84,4 @@ def compare_version(self, a: str , b: str):
         elif (aMajor, aMinor, aRev) > (bMajor, bMinor, bRev):
             return 1
         else:
-            return 0
\ No newline at end of file
+            return 0