From c337c341ed9a13e357807e818d8500fb51c79a1f Mon Sep 17 00:00:00 2001 From: "Alexander.A.Utkin" Date: Tue, 27 Aug 2024 12:36:41 +0300 Subject: [PATCH] Rework API py: removes commit(), adds delete_meta() methods --- README.md | 33 ++++--- pyreindexer/CMakeLists.txt | 11 ++- pyreindexer/index_definition.py | 19 ++-- pyreindexer/lib/include/pyobjtools.cc | 10 +- pyreindexer/lib/src/rawpyreindexer.cc | 25 ++--- pyreindexer/lib/src/rawpyreindexer.h | 4 +- pyreindexer/lib/src/reindexerinterface.h | 8 +- pyreindexer/query_results.py | 4 +- pyreindexer/rx_connector.py | 118 ++++++++++------------- pyreindexer/tests/helpers/log_helper.py | 5 +- pyreindexer/tests/helpers/metadata.py | 7 ++ pyreindexer/tests/test_data/constants.py | 87 +++++++++-------- pyreindexer/tests/tests/test_metadata.py | 14 +++ 13 files changed, 179 insertions(+), 166 deletions(-) diff --git a/README.md b/README.md index f3b5c28..de8383e 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ Gets a list of namespaces available __Arguments:__ - enum_not_opeden (bool, optional): An enumeration mode flag. If it is + enum_not_opened (bool, optional): An enumeration mode flag. If it is set then closed namespaces are in result list too. Defaults to False. __Returns:__ @@ -238,16 +238,18 @@ __Raises:__ Exception: Raises with an error message of API return on non-zero error code. -

commit

+

meta_put

```python -RxConnector.commit(self, namespace) +RxConnector.meta_put(self, namespace, key, value) ``` -Flushes changes to a storage of Reindexer +Puts metadata to a storage of Reindexer by key __Arguments:__ namespace (string): A name of a namespace + key (string): A key in a storage of Reindexer for metadata keeping + value (string): A metadata for storage __Raises:__ @@ -255,18 +257,21 @@ __Raises:__ Exception: Raises with an error message of API return on non-zero error code. -

meta_put

+

meta_get

```python -RxConnector.meta_put(self, namespace, key, value) +RxConnector.meta_get(self, namespace, key) ``` -Puts metadata to a storage of Reindexer by key +Gets metadata from a storage of Reindexer by key specified __Arguments:__ namespace (string): A name of a namespace - key (string): A key in a storage of Reindexer for metadata keeping - value (string): A metadata for storage + key (string): A key in a storage of Reindexer where metadata is kept + +__Returns:__ + + string: A metadata value __Raises:__ @@ -274,22 +279,18 @@ __Raises:__ Exception: Raises with an error message of API return on non-zero error code. -

meta_get

+

meta_delete

```python -RxConnector.meta_get(self, namespace, key) +RxConnector.meta_delete(self, namespace, key) ``` -Gets metadata from a storage of Reindexer by key specified +Deletes metadata from a storage of Reindexer by key specified __Arguments:__ namespace (string): A name of a namespace key (string): A key in a storage of Reindexer where metadata is kept -__Returns:__ - - string: A metadata value - __Raises:__ Exception: Raises with an error message of API return if Reindexer instance is not initialized yet. diff --git a/pyreindexer/CMakeLists.txt b/pyreindexer/CMakeLists.txt index 5f817dd..1e0236f 100644 --- a/pyreindexer/CMakeLists.txt +++ b/pyreindexer/CMakeLists.txt @@ -2,7 +2,14 @@ cmake_minimum_required(VERSION 3.0..3.13) project(pyreindexer) -set(CMAKE_CXX_STANDARD 17) +# Configure cmake options +if(MSVC) + # Enable C++20 for windows build to be able to use designated initializers. + # GCC/Clang support them even with C++17. + set(CMAKE_CXX_STANDARD 20) +else() + set(CMAKE_CXX_STANDARD 17) +endif() set(CMAKE_CXX_STANDARD_REQUIRED ON) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "RelWithDebInfo") @@ -11,7 +18,7 @@ endif() enable_testing() set(PY_MIN_VERSION 3.6) -set(RX_MIN_VERSION 3.2.2) +set(RX_MIN_VERSION 3.24.0) find_package(PythonInterp ${PY_MIN_VERSION}) find_package(PythonLibs ${PY_MIN_VERSION}) find_package(reindexer CONFIG ${RX_MIN_VERSION}) diff --git a/pyreindexer/index_definition.py b/pyreindexer/index_definition.py index 3c7c7c7..c1a7664 100644 --- a/pyreindexer/index_definition.py +++ b/pyreindexer/index_definition.py @@ -11,17 +11,21 @@ class IndexDefinition(dict): # Arguments: name (str): An index name. json_paths (:obj:`list` of :obj:`str`): A name for mapping a value to a json field. - field_type (str): A type of a field. Possible values are: `int`, `int64`, `double`, `string`, `bool`, `composite`. + field_type (str): A type of field. Possible values are: `int`, `int64`, `double`, `string`, `bool`, `composite`. index_type (str): An index type. Possible values are: `hash`, `tree`, `text`, `-`. is_pk (bool): True if a field is a primary key. is_array (bool): True if an index is an array. - is_dense (bool): True if an index is dense. reduce index size. Saves 8 bytes per unique key value for 'hash' and 'tree' index types. - For '-' index type saves 4-8 bytes per each element. Useful for indexes with high selectivity, but for tree and hash indexes with low selectivity could + is_dense (bool): True if an index is dense. reduce index size. Saves 8 bytes per unique key value for 'hash' + and 'tree' index types. + For '-' index type saves 4-8 bytes per each element. Useful for indexes with high selectivity, + but for tree and hash indexes with low selectivity could significantly decrease update performance. is_sparse (bool): True if a value of an index may be not presented. - collate_mode (str): Sets an order of values by collate mode. Possible values are: `none`, `ascii`, `utf8`, `numeric`, `custom`. + collate_mode (str): Sets an order of values by collate mode. Possible values are: + `none`, `ascii`, `utf8`, `numeric`, `custom`. sort_order_letters (str): Order for a sort sequence for a custom collate mode. - config (dict): A config for a fulltext engine. [More](https://github.com/Restream/reindexer/blob/master/fulltext.md) . + config (dict): A config for a fulltext engine. + [More](https://github.com/Restream/reindexer/blob/master/fulltext.md) . """ def __getitem__(self, attr): @@ -33,11 +37,12 @@ def __setitem__(self, attr, value): super(IndexDefinition, self).update({attr: value}) return self - def update(self, dict_part={}): + def update(self, dict_part=None): raise NotImplementedError( 'Bulk update is not implemented for IndexDefinition instance') - def _get_known_attrs(self): + @staticmethod + def _get_known_attrs() -> list[str]: return ['name', 'json_paths', 'field_type', 'index_type', 'is_pk', 'is_array', 'is_dense', 'is_sparse', 'collate_mode', 'sort_order_letters', 'expire_after', 'config'] diff --git a/pyreindexer/lib/include/pyobjtools.cc b/pyreindexer/lib/include/pyobjtools.cc index 7458a5f..35a31a7 100644 --- a/pyreindexer/lib/include/pyobjtools.cc +++ b/pyreindexer/lib/include/pyobjtools.cc @@ -87,15 +87,13 @@ void pyDictSerialize(PyObject **dict, reindexer::WrSerializer &wrSer) { } void PyObjectToJson(PyObject **obj, reindexer::WrSerializer &wrSer) { - if (!PyList_Check(*obj) && !PyDict_Check(*obj)) { - throw reindexer::Error(errParseJson, - std::string("PyObject must be a dictionary or a list for JSON serializing, got ") + Py_TYPE(*obj)->tp_name); - } - if (PyDict_Check(*obj)) { pyDictSerialize(obj, wrSer); - } else { + } else if (PyList_Check(*obj) ) { pyListSerialize(obj, wrSer); + } else { + throw reindexer::Error(errParseJson, + std::string("PyObject must be a dictionary or a list for JSON serializing, got ") + Py_TYPE(*obj)->tp_name); } } diff --git a/pyreindexer/lib/src/rawpyreindexer.cc b/pyreindexer/lib/src/rawpyreindexer.cc index c650af4..a178e4e 100644 --- a/pyreindexer/lib/src/rawpyreindexer.cc +++ b/pyreindexer/lib/src/rawpyreindexer.cc @@ -269,35 +269,37 @@ static PyObject *ItemUpsert(PyObject *self, PyObject *args) { return itemModify( static PyObject *ItemDelete(PyObject *self, PyObject *args) { return itemModify(self, args, ModeDelete); } -static PyObject *Commit(PyObject *self, PyObject *args) { +static PyObject *PutMeta(PyObject *self, PyObject *args) { uintptr_t rx; char *ns; + char *key; + char *value; - if (!PyArg_ParseTuple(args, "ks", &rx, &ns)) { + if (!PyArg_ParseTuple(args, "ksss", &rx, &ns, &key, &value)) { return NULL; } - Error err = getDB(rx)->Commit(ns); + Error err = getDB(rx)->PutMeta(ns, key, value); return pyErr(err); } -static PyObject *PutMeta(PyObject *self, PyObject *args) { +static PyObject *GetMeta(PyObject *self, PyObject *args) { uintptr_t rx; char *ns; char *key; - char *value; - if (!PyArg_ParseTuple(args, "ksss", &rx, &ns, &key, &value)) { + if (!PyArg_ParseTuple(args, "kss", &rx, &ns, &key)) { return NULL; } - Error err = getDB(rx)->PutMeta(ns, key, value); + std::string value; + Error err = getDB(rx)->GetMeta(ns, key, value); - return pyErr(err); + return Py_BuildValue("iss", err.code(), err.what().c_str(), value.c_str()); } -static PyObject *GetMeta(PyObject *self, PyObject *args) { +static PyObject *DeleteMeta(PyObject *self, PyObject *args) { uintptr_t rx; char *ns; char *key; @@ -306,10 +308,9 @@ static PyObject *GetMeta(PyObject *self, PyObject *args) { return NULL; } - std::string value; - Error err = getDB(rx)->GetMeta(ns, key, value); + Error err = getDB(rx)->DeleteMeta(ns, key); - return Py_BuildValue("iss", err.code(), err.what().c_str(), value.c_str()); + return pyErr(err); } static PyObject *Select(PyObject *self, PyObject *args) { diff --git a/pyreindexer/lib/src/rawpyreindexer.h b/pyreindexer/lib/src/rawpyreindexer.h index b3a18ac..153a555 100644 --- a/pyreindexer/lib/src/rawpyreindexer.h +++ b/pyreindexer/lib/src/rawpyreindexer.h @@ -64,9 +64,9 @@ static PyObject *ItemInsert(PyObject *self, PyObject *args); static PyObject *ItemUpdate(PyObject *self, PyObject *args); static PyObject *ItemUpsert(PyObject *self, PyObject *args); static PyObject *ItemDelete(PyObject *self, PyObject *args); -static PyObject *Commit(PyObject *self, PyObject *args); static PyObject *PutMeta(PyObject *self, PyObject *args); static PyObject *GetMeta(PyObject *self, PyObject *args); +static PyObject *DeleteMeta(PyObject *self, PyObject *args); static PyObject *Select(PyObject *self, PyObject *args); static PyObject *EnumMeta(PyObject *self, PyObject *args); static PyObject *EnumNamespaces(PyObject *self, PyObject *args); @@ -90,9 +90,9 @@ static PyMethodDef module_methods[] = { {"item_update", ItemUpdate, METH_VARARGS, "update item"}, {"item_upsert", ItemUpsert, METH_VARARGS, "upsert item"}, {"item_delete", ItemDelete, METH_VARARGS, "delete item"}, - {"commit", Commit, METH_VARARGS, "commit"}, {"meta_put", PutMeta, METH_VARARGS, "put meta"}, {"meta_get", GetMeta, METH_VARARGS, "get meta"}, + {"meta_delete", DeleteMeta, METH_VARARGS, "delete meta"}, {"meta_enum", EnumMeta, METH_VARARGS, "enum meta"}, {"select", Select, METH_VARARGS, "select query"}, diff --git a/pyreindexer/lib/src/reindexerinterface.h b/pyreindexer/lib/src/reindexerinterface.h index 574d10a..435d857 100644 --- a/pyreindexer/lib/src/reindexerinterface.h +++ b/pyreindexer/lib/src/reindexerinterface.h @@ -92,15 +92,15 @@ class ReindexerInterface { Error Delete(std::string_view ns, typename DBT::ItemT& item) { return execute([this, ns, &item] { return deleteImpl(ns, item); }); } - Error Commit(std::string_view ns) { - return execute([this, ns] { return commit(ns); }); - } Error PutMeta(std::string_view ns, const std::string& key, std::string_view data) { return execute([this, ns, &key, data] { return putMeta(ns, key, data); }); } Error GetMeta(std::string_view ns, const std::string& key, std::string& data) { return execute([this, ns, &key, &data] { return getMeta(ns, key, data); }); } + Error DeleteMeta(std::string_view ns, const std::string& key) { + return execute([this, ns, &key] { return deleteMeta(ns, key); }); + } Error EnumMeta(std::string_view ns, std::vector& keys) { return execute([this, ns, &keys] { return enumMeta(ns, keys); }); } @@ -125,9 +125,9 @@ class ReindexerInterface { Error upsert(std::string_view ns, typename DBT::ItemT& item) { return db_.Upsert({ns.data(), ns.size()}, item); } Error update(std::string_view ns, typename DBT::ItemT& item) { return db_.Update({ns.data(), ns.size()}, item); } Error deleteImpl(std::string_view ns, typename DBT::ItemT& item) { return db_.Delete({ns.data(), ns.size()}, item); } - Error commit(std::string_view ns) { return db_.Commit({ns.data(), ns.size()}); } Error putMeta(std::string_view ns, const std::string& key, std::string_view data) { return db_.PutMeta({ns.data(), ns.size()}, key, {data.data(), data.size()}); } Error getMeta(std::string_view ns, const std::string& key, std::string& data) { return db_.GetMeta({ns.data(), ns.size()}, key, data); } + Error deleteMeta(std::string_view ns, const std::string& key) { return db_.DeleteMeta({ns.data(), ns.size()}, key); } Error enumMeta(std::string_view ns, std::vector& keys) { return db_.EnumMeta({ns.data(), ns.size()}, keys); } Error select(const std::string &query, typename DBT::QueryResultsT& result) { return db_.Select(query, result); } Error enumNamespaces(std::vector& defs, EnumNamespacesOpts opts) { return db_.EnumNamespaces(defs, opts); } diff --git a/pyreindexer/query_results.py b/pyreindexer/query_results.py index 32c90ab..0b62c1a 100644 --- a/pyreindexer/query_results.py +++ b/pyreindexer/query_results.py @@ -45,11 +45,11 @@ def __next__(self): self.pos += 1 self.err_code, self.err_msg, res = self.api.query_results_iterate( self.qres_wrapper_ptr) - if (self.err_code): + if self.err_code: raise Exception(self.err_msg) return res else: - del(self) + del self raise StopIteration def __del__(self): diff --git a/pyreindexer/rx_connector.py b/pyreindexer/rx_connector.py index 99f08ba..dbb51a9 100644 --- a/pyreindexer/rx_connector.py +++ b/pyreindexer/rx_connector.py @@ -3,10 +3,10 @@ class RxConnector(RaiserMixin): - """ RxConnector provides a binding to Reindexer upon two shared libraries (hereinafter - APIs): 'rawpyreindexerb.so' and 'rawpyreindexerc.so'. - The first one is aimed to a builtin way usage. That API embeds Reindexer so it could be used right in-place as is. - The second one acts as a lightweight client which establishes a connection to Reindexer server via RPC. - The APIs interfaces are completely the same. + """ RxConnector provides a binding to Reindexer upon two shared libraries (hereinafter - APIs): 'rawpyreindexerb.so' + and 'rawpyreindexerc.so'. The first one is aimed to a builtin way usage. That API embeds Reindexer, so it could be + used right in-place as is. The second one acts as a lightweight client which establishes a connection to Reindexer + server via RPC. The APIs interfaces are completely the same. # Attributes: api (module): An API module loaded dynamically for Reindexer calls @@ -21,7 +21,8 @@ def __init__(self, dsn): Initializes an error code and a Reindexer instance descriptor to zero. # Arguments: - dsn (string): The connection string which contains a protocol. Examples: 'builtin:///tmp/pyrx', 'cproto://127.0.0.1:6534/pyrx + dsn (string): The connection string which contains a protocol. + Examples: 'builtin:///tmp/pyrx', 'cproto://127.0.0.1:6534/pyrx """ @@ -42,9 +43,6 @@ def __del__(self): def close(self): """Closes an API instance with Reindexer resources freeing - # Returns: - None - """ self._api_close() @@ -62,8 +60,7 @@ def namespace_open(self, namespace): """ self.raise_on_not_init() - self.err_code, self.err_msg = self.api.namespace_open( - self.rx, namespace) + self.err_code, self.err_msg = self.api.namespace_open(self.rx, namespace) self.raise_on_error() def namespace_close(self, namespace): @@ -79,8 +76,7 @@ def namespace_close(self, namespace): """ self.raise_on_not_init() - self.err_code, self.err_msg = self.api.namespace_close( - self.rx, namespace) + self.err_code, self.err_msg = self.api.namespace_close(self.rx, namespace) self.raise_on_error() def namespace_drop(self, namespace): @@ -96,15 +92,14 @@ def namespace_drop(self, namespace): """ self.raise_on_not_init() - self.err_code, self.err_msg = self.api.namespace_drop( - self.rx, namespace) + self.err_code, self.err_msg = self.api.namespace_drop(self.rx, namespace) self.raise_on_error() def namespaces_enum(self, enum_not_opened=False): """Gets a list of namespaces available # Arguments: - enum_not_opeden (bool, optional): An enumeration mode flag. If it is + enum_not_opened (bool, optional): An enumeration mode flag. If it is set then closed namespaces are in result list too. Defaults to False. # Returns: @@ -117,8 +112,7 @@ def namespaces_enum(self, enum_not_opened=False): """ self.raise_on_not_init() - self.err_code, self.err_msg, res = self.api.namespaces_enum( - self.rx, enum_not_opened) + self.err_code, self.err_msg, res = self.api.namespaces_enum(self.rx, enum_not_opened) self.raise_on_error() return res @@ -127,7 +121,7 @@ def index_add(self, namespace, index_def): # Arguments: namespace (string): A name of a namespace - index_def (dict): A dictionary of index definiton + index_def (dict): A dictionary of index definition # Raises: Exception: Raises with an error message of API return if Reindexer instance is not initialized yet. @@ -136,8 +130,7 @@ def index_add(self, namespace, index_def): """ self.raise_on_not_init() - self.err_code, self.err_msg = self.api.index_add( - self.rx, namespace, index_def) + self.err_code, self.err_msg = self.api.index_add(self.rx, namespace, index_def) self.raise_on_error() def index_update(self, namespace, index_def): @@ -145,7 +138,7 @@ def index_update(self, namespace, index_def): # Arguments: namespace (string): A name of a namespace - index_def (dict): A dictionary of index definiton + index_def (dict): A dictionary of index definition # Raises: Exception: Raises with an error message of API return if Reindexer instance is not initialized yet. @@ -154,8 +147,7 @@ def index_update(self, namespace, index_def): """ self.raise_on_not_init() - self.err_code, self.err_msg = self.api.index_update( - self.rx, namespace, index_def) + self.err_code, self.err_msg = self.api.index_update(self.rx, namespace, index_def) self.raise_on_error() def index_drop(self, namespace, index_name): @@ -172,11 +164,10 @@ def index_drop(self, namespace, index_name): """ self.raise_on_not_init() - self.err_code, self.err_msg = self.api.index_drop( - self.rx, namespace, index_name) + self.err_code, self.err_msg = self.api.index_drop(self.rx, namespace, index_name) self.raise_on_error() - def item_insert(self, namespace, item_def, precepts=[]): + def item_insert(self, namespace, item_def, precepts=None): """Inserts an item with its precepts to the namespace specified. # Arguments: @@ -190,12 +181,13 @@ def item_insert(self, namespace, item_def, precepts=[]): """ + if precepts is None: + precepts = [] self.raise_on_not_init() - self.err_code, self.err_msg = self.api.item_insert( - self.rx, namespace, item_def, precepts) + self.err_code, self.err_msg = self.api.item_insert(self.rx, namespace, item_def, precepts) self.raise_on_error() - def item_update(self, namespace, item_def, precepts=[]): + def item_update(self, namespace, item_def, precepts=None): """Updates an item with its precepts in the namespace specified. # Arguments: @@ -209,13 +201,14 @@ def item_update(self, namespace, item_def, precepts=[]): """ + if precepts is None: + precepts = [] self.raise_on_not_init() - self.err_code, self.err_msg = self.api.item_update( - self.rx, namespace, item_def, precepts) + self.err_code, self.err_msg = self.api.item_update(self.rx, namespace, item_def, precepts) self.raise_on_error() - def item_upsert(self, namespace, item_def, precepts=[]): - """Updates an item with its precepts in the namespace specified. Creates the item if it not exist. + def item_upsert(self, namespace, item_def, precepts=None): + """Updates an item with its precepts in the namespace specified. Creates the item if it not exists. # Arguments: namespace (string): A name of a namespace @@ -228,9 +221,10 @@ def item_upsert(self, namespace, item_def, precepts=[]): """ + if precepts is None: + precepts = [] self.raise_on_not_init() - self.err_code, self.err_msg = self.api.item_upsert( - self.rx, namespace, item_def, precepts) + self.err_code, self.err_msg = self.api.item_upsert(self.rx, namespace, item_def, precepts) self.raise_on_error() def item_delete(self, namespace, item_def): @@ -247,15 +241,16 @@ def item_delete(self, namespace, item_def): """ self.raise_on_not_init() - self.err_code, self.err_msg = self.api.item_delete( - self.rx, namespace, item_def) + self.err_code, self.err_msg = self.api.item_delete(self.rx, namespace, item_def) self.raise_on_error() - def commit(self, namespace): - """Flushes changes to a storage of Reindexer + def meta_put(self, namespace, key, value): + """Puts metadata to a storage of Reindexer by key # Arguments: - namespace (string): A name of a namespace + namespace (string): A name of a namespace + key (string): A key in a storage of Reindexer for metadata keeping + value (string): A metadata for storage # Raises: Exception: Raises with an error message of API return if Reindexer instance is not initialized yet. @@ -264,17 +259,18 @@ def commit(self, namespace): """ self.raise_on_not_init() - self.err_code, self.err_msg = self.api.commit( - self.rx, namespace) + self.err_code, self.err_msg = self.api.meta_put(self.rx, namespace, key, value) self.raise_on_error() - def meta_put(self, namespace, key, value): - """Puts metadata to a storage of Reindexer by key + def meta_get(self, namespace, key): + """Gets metadata from a storage of Reindexer by key specified # Arguments: namespace (string): A name of a namespace - key (string): A key in a storage of Reindexer for metadata keeping - value (string): A metadata for storage + key (string): A key in a storage of Reindexer where metadata is kept + + # Returns: + string: A metadata value # Raises: Exception: Raises with an error message of API return if Reindexer instance is not initialized yet. @@ -283,20 +279,17 @@ def meta_put(self, namespace, key, value): """ self.raise_on_not_init() - self.err_code, self.err_msg = self.api.meta_put( - self.rx, namespace, key, value) + self.err_code, self.err_msg, res = self.api.meta_get(self.rx, namespace, key) self.raise_on_error() + return res - def meta_get(self, namespace, key): - """Gets metadata from a storage of Reindexer by key specified + def meta_delete(self, namespace, key): + """Deletes metadata from a storage of Reindexer by key specified # Arguments: namespace (string): A name of a namespace key (string): A key in a storage of Reindexer where metadata is kept - # Returns: - string: A metadata value - # Raises: Exception: Raises with an error message of API return if Reindexer instance is not initialized yet. Exception: Raises with an error message of API return on non-zero error code. @@ -304,10 +297,8 @@ def meta_get(self, namespace, key): """ self.raise_on_not_init() - self.err_code, self.err_msg, res = self.api.meta_get( - self.rx, namespace, key) + self.err_code, self.err_msg = self.api.meta_delete(self.rx, namespace, key) self.raise_on_error() - return res def meta_enum(self, namespace): """Gets a list of metadata keys from a storage of Reindexer @@ -325,8 +316,7 @@ def meta_enum(self, namespace): """ self.raise_on_not_init() - self.err_code, self.err_msg, res = self.api.meta_enum( - self.rx, namespace) + self.err_code, self.err_msg, res = self.api.meta_enum(self.rx, namespace) self.raise_on_error() return res @@ -346,8 +336,7 @@ def select(self, query): """ self.raise_on_not_init() - self.err_code, self.err_msg, qres_wrapper_ptr, qres_iter_count = self.api.select( - self.rx, query) + self.err_code, self.err_msg, qres_wrapper_ptr, qres_iter_count = self.api.select(self.rx, query) self.raise_on_error() return QueryResults(self.api, qres_wrapper_ptr, qres_iter_count) @@ -357,9 +346,6 @@ def _api_import(self, dsn): # Arguments: dsn (string): The connection string which contains a protocol. - # Returns: - None - # Raises: Exception: Raises an exception if a connection protocol is unrecognized. @@ -380,9 +366,6 @@ def _api_init(self, dsn): # Arguments: dsn (string): The connection string which contains a protocol. - # Returns: - None - # Raises: Exception: Raises with an error message of API return if Reindexer instance is not initialized yet. Exception: Raises with an error message of API return on non-zero error code. @@ -397,9 +380,6 @@ def _api_init(self, dsn): def _api_close(self): """Destructs Reindexer instance correctly and resets memory pointer. - # Returns: - None - # Raises: Exception: Raises with an error message of API return if Reindexer instance is not initialized yet. diff --git a/pyreindexer/tests/helpers/log_helper.py b/pyreindexer/tests/helpers/log_helper.py index df24947..cc5dd4b 100644 --- a/pyreindexer/tests/helpers/log_helper.py +++ b/pyreindexer/tests/helpers/log_helper.py @@ -8,9 +8,10 @@ class OneLineExceptionFormatter(logging.Formatter): """ One line log output https://docs.python.org/2/howto/logging-cookbook.html#logging-cookbook """ + def formatException(self, exc_info): result = super(OneLineExceptionFormatter, self).formatException(exc_info) - return repr(result) # or format into one line however you want to + return repr(result) # or format into one line however you want to def format(self, record): result = super(OneLineExceptionFormatter, self).format(record) @@ -34,7 +35,7 @@ def format(self, record): # Save log to file log_folder = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../logs/') if not os.path.exists(log_folder): - os.makedirs(log_folder) + os.makedirs(log_folder) log_filename = os.path.join(os.path.dirname(log_folder), 'test_run_%s.txt' % (datetime.now().strftime('%d%b-%H:%M:%S'))) file_handler = logging.FileHandler(log_filename) diff --git a/pyreindexer/tests/helpers/metadata.py b/pyreindexer/tests/helpers/metadata.py index 6e7a117..36a1622 100644 --- a/pyreindexer/tests/helpers/metadata.py +++ b/pyreindexer/tests/helpers/metadata.py @@ -20,3 +20,10 @@ def get_metadata_by_key(namespace, key): value = db.meta_get(namespace_name, key) log_operation.info(f"Get metadata value by key: '{key}: {value}'") return value + + +def delete_metadata_by_key(namespace, key): + db, namespace_name = namespace + db.meta_delete(namespace_name, key) + log_operation.info(f"Delete metadata value from namespace '{namespace_name}' by key '{key}'") + return key diff --git a/pyreindexer/tests/test_data/constants.py b/pyreindexer/tests/test_data/constants.py index ef06020..71cc47c 100644 --- a/pyreindexer/tests/test_data/constants.py +++ b/pyreindexer/tests/test_data/constants.py @@ -1,57 +1,56 @@ index_definition = { - "name": "id", - "field_type": "int", - "index_type": "hash", - "is_pk": True, - "is_array": False, - "is_dense": False, - "is_sparse": False, - "collate_mode": "none", - "sort_order_letters": "", - "expire_after": 0, - "config": { + "name": "id", + "field_type": "int", + "index_type": "hash", + "is_pk": True, + "is_array": False, + "is_dense": False, + "is_sparse": False, + "collate_mode": "none", + "sort_order_letters": "", + "expire_after": 0, + "config": { - }, - "json_paths": [ - "id" - ] + }, + "json_paths": [ + "id" + ] } updated_index_definition = { - "name": "id", - "field_type": "int64", - "index_type": "hash", - "is_pk": True, - "is_array": False, - "is_dense": False, - "is_sparse": False, - "collate_mode": "none", - "sort_order_letters": "", - "expire_after": 0, - "config": { + "name": "id", + "field_type": "int64", + "index_type": "hash", + "is_pk": True, + "is_array": False, + "is_dense": False, + "is_sparse": False, + "collate_mode": "none", + "sort_order_letters": "", + "expire_after": 0, + "config": { - }, - "json_paths": [ - "id_new" - ] + }, + "json_paths": [ + "id_new" + ] } special_namespaces = [{"name": "#namespaces"}, - {"name": "#memstats"}, - {"name": "#perfstats"}, - {"name": "#config"}, - {"name": "#queriesperfstats"}, - {"name": "#activitystats"}, - {"name": "#clientsstats"}] + {"name": "#memstats"}, + {"name": "#perfstats"}, + {"name": "#config"}, + {"name": "#queriesperfstats"}, + {"name": "#activitystats"}, + {"name": "#clientsstats"}] special_namespaces_cluster = [{"name": "#namespaces"}, - {"name": "#memstats"}, - {"name": "#perfstats"}, - {"name": "#config"}, - {"name": "#queriesperfstats"}, - {"name": "#activitystats"}, - {"name": "#clientsstats"}, - {"name": "#replicationstats"}] + {"name": "#memstats"}, + {"name": "#perfstats"}, + {"name": "#config"}, + {"name": "#queriesperfstats"}, + {"name": "#activitystats"}, + {"name": "#clientsstats"}, + {"name": "#replicationstats"}] item_definition = {'id': 100, 'val': "testval"} - diff --git a/pyreindexer/tests/tests/test_metadata.py b/pyreindexer/tests/tests/test_metadata.py index c133d09..22519f7 100644 --- a/pyreindexer/tests/tests/test_metadata.py +++ b/pyreindexer/tests/tests/test_metadata.py @@ -47,3 +47,17 @@ def test_update_metadata(self, namespace, metadata): # Then ("Check that metadata was updated") updated_value = get_metadata_by_key(namespace, meta_key) assert_that(updated_value, equal_to(new_meta_value), "Can't update metadata") + + def test_delete_metadata(self, namespace, metadata): + # Given ("Put metadata to namespace") + meta_key, meta_value = metadata + # When ("Delete metadata") + delete_metadata_by_key(namespace, meta_key) + # Then ("Check that metadata was removed") + read_value = get_metadata_by_key(namespace, meta_key) + assert_that(read_value, equal_to(''), "Can't delete metadata") + # When ("Get list of metadata keys") + meta_list = get_metadata_keys(namespace) + # Then ("Check that list of metadata is empty") + assert_that(meta_list, has_length(0), "Metadata is not empty") + assert_that(meta_list, equal_to([]), "Metadata is not empty")