diff --git a/include/ircd/db.h b/include/ircd/db.h index 271fd8f30..f5d78062e 100644 --- a/include/ircd/db.h +++ b/include/ircd/db.h @@ -142,7 +142,7 @@ enum ircd::db::op #include "db/index.h" #include "db/json.h" #include "db/iov.h" -#include "db/where.h" +#include "db/query.h" #include "db/cursor.h" namespace ircd diff --git a/include/ircd/db/cursor.h b/include/ircd/db/cursor.h index 53496d6a4..b0a550bb4 100644 --- a/include/ircd/db/cursor.h +++ b/include/ircd/db/cursor.h @@ -36,11 +36,11 @@ struct ircd::db::cursor struct const_reverse_iterator; struct const_iterator; - using where_type = db::where; + template using query_type = db::query; using iterator_type = const_iterator; struct index index; - const where_type *where{nullptr}; + const query_type<> *query{nullptr}; const_iterator end(const string_view &key = {}); const_iterator begin(const string_view &key = {}); @@ -48,9 +48,9 @@ struct ircd::db::cursor const_reverse_iterator rend(const string_view &key = {}); const_reverse_iterator rbegin(const string_view &key = {}); - cursor(const string_view &index, const where_type *const &where = nullptr) + cursor(const string_view &index, const query_type<> *const &query = nullptr) :index{*d, index} - ,where{where} + ,query{query} {} }; @@ -64,9 +64,9 @@ struct ircd::db::cursor::const_iterator_base using reference = value_type &; using difference_type = size_t; using iterator_category = std::bidirectional_iterator_tag; - using where_type = cursor::where_type; + template using query_type = cursor::query_type; - const where_type *where{nullptr}; + const query_type<> *query{nullptr}; index_iterator idx; db::row row; mutable tuple v; @@ -170,7 +170,7 @@ template ircd::db::cursor::const_iterator_base::const_iterator_base(const cursor &c, index_iterator idx, const gopts &opts) -:where{c.where} +:query{c.query} ,idx{std::move(idx)} ,row { @@ -193,10 +193,10 @@ ircd::db::cursor::const_iterator_base::const_iterator_ if(invalid) return; - if(!this->where) + if(!this->query) return; - if(!(*this->where)(this->operator*())) + if(!(*this->query)(this->operator*())) this->operator++(); } @@ -236,7 +236,7 @@ ircd::db::cursor::const_iterator_base::seek_row() return false; stale = true; - if(this->where && !(*this->where)(this->operator*())) + if(this->query && !(*this->query)(this->operator*())) return false; return true; diff --git a/include/ircd/db/query.h b/include/ircd/db/query.h new file mode 100644 index 000000000..5935be98c --- /dev/null +++ b/include/ircd/db/query.h @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2016 Charybdis Development Team + * Copyright (C) 2016 Jason Volk + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#pragma once +#define HAVE_IRCD_DB_QUERY_H + +namespace ircd::db +{ + /// Types of query clauses. + enum class where + { + noop, + test, + equal, + not_equal, + logical_or, + logical_and, + logical_not, + }; + + string_view reflect(const where &); + + /// The query provides a decision tree oriented around the structure of + /// a tuple. All queries inherit from query<> which can execute the + /// derived's test via the virtual operator(). The abstract query instance + /// stores the type of its derived portion for downcasting. Downcasting is + /// used to get more information from the query to get a result faster, ex. + /// where::equal, the keys being tested might impact the db fetch pattern. + /// or searching a logic tree of where::logical_* for the most efficient + /// db fetches to make next. + template struct query; + + template struct query; + template struct query; + template struct query; + template struct query; + template struct query; + template struct query; + template struct query; +} + +template +struct ircd::db::query +{ + virtual bool operator()(const tuple &) const + { + return true; + } + + // Stores the type of the derived class for downcasting. This is important + // in order to evaluate details of the query. + where type; + + query(const enum where &type = where::noop) + :type{type} + {} + + virtual ~query() noexcept {} +}; + +template +struct ircd::db::query +:query +{ + using function = std::function; + + function closure; + + bool operator()(const tuple &t) const override + { + return closure(t); + } + + query(function closure) + :query{where::test} + ,closure{std::move(closure)} + {} +}; + +template +struct ircd::db::query +:query +{ + tuple value; + + bool operator()(const tuple &) const override; + + query(const tuple &value) + :query{where::equal} + ,value{value} + {} + + query(const json::members &members) + :query{where::equal} + ,value{members} + {} +}; + +template +bool +ircd::db::query::operator()(const tuple &value) +const +{ + return json::until(this->value, value, [] + (const auto &key, const auto &a, const auto &b) + { + if(!a) + return true; + + return a == b; + }); +} + +template +struct ircd::db::query +:query +{ + tuple value; + + bool operator()(const tuple &) const override; + + query(const tuple &value) + :query{where::not_equal} + ,value{value} + {} + + query(const json::members &members) + :query{where::not_equal} + ,value{members} + {} +}; + +template +bool +ircd::db::query::operator()(const tuple &value) +const +{ + return !json::until(this->value, value, [] + (const auto &key, const auto &a, const auto &b) + { + if(!a) + return true; + + return a == b; + }); +} + +template +struct ircd::db::query +:query +{ + const query *a, *b; + + bool operator()(const tuple &t) const override + { + return (*a)(t) || (*b)(t); + } + + query(const query &a, const query &b) + :query{where::logical_or} + ,a{&a} + ,b{&b} + {} +}; + +template +struct ircd::db::query +:query +{ + const query *a, *b; + + bool operator()(const tuple &t) const override + { + return (*a)(t) && (*b)(t); + } + + query(const query &a, const query &b) + :query{where::logical_and} + ,a{&a} + ,b{&b} + {} +}; + +template +struct ircd::db::query +:query +{ + const where *a; + + bool operator()(const tuple &t) const override + { + return !(*a)(t); + } + + query(const where &a) + :query{where::logical_not} + ,a{&a} + {} +}; + +namespace ircd::db +{ + template typename db::query operator||(const query &a, const query &b) + { + return { a, b }; + } + + template typename db::query operator&&(const query &a, const query &b) + { + return { a, b }; + } + + template typename db::query operator!(const query &a) + { + return { a }; + } +} diff --git a/include/ircd/db/where.h b/include/ircd/db/where.h deleted file mode 100644 index fa24e672a..000000000 --- a/include/ircd/db/where.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (C) 2016 Charybdis Development Team - * Copyright (C) 2016 Jason Volk - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice is present in all copies. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -#pragma once -#define HAVE_IRCD_DB_WHERE_H - -namespace ircd::db -{ - template struct where; -} - -template -struct ircd::db::where -{ - struct equal; - struct not_equal; - struct logical_not; - struct logical_and; - struct logical_or; - struct test; - struct noop; - - virtual bool operator()(const tuple &) const = 0; - virtual ~where() noexcept = default; -}; - -namespace ircd::db -{ - template typename where::logical_or operator||(const where &, const where &); - template typename where::logical_and operator&&(const where &, const where &); - template typename where::logical_not operator!(const where &); -} - -template -struct ircd::db::where::equal -:ircd::db::where -{ - tuple value; - - bool operator()(const tuple &) const override; - - equal(const tuple &value) - :value{value} - {} - - equal(const json::members &members) - :value{members} - {} -}; - -template -bool -ircd::db::where::equal::operator()(const tuple &value) -const -{ - return json::until(this->value, value, [] - (const auto &key, const auto &a, const auto &b) - { - if(!a) - return true; - - return a == b; - }); -} - -template -struct ircd::db::where::not_equal -:ircd::db::where -{ - tuple value; - - bool operator()(const tuple &) const override; - - not_equal(const tuple &value) - :value{value} - {} - - not_equal(const json::members &members) - :value{members} - {} -}; - -template -bool -ircd::db::where::not_equal::operator()(const tuple &value) -const -{ - return !json::until(this->value, value, [] - (const auto &key, const auto &a, const auto &b) - { - if(!a) - return true; - - return a == b; - }); -} - -template -struct ircd::db::where::logical_and -:ircd::db::where -{ - const where *a, *b; - - bool operator()(const tuple &t) const override - { - return (*a)(t) && (*b)(t); - } - - logical_and(const where &a, const where &b) - :a{&a} - ,b{&b} - {} -}; - -template -typename ircd::db::where::logical_and -ircd::db::operator&&(const where &a, const where &b) -{ - return { a, b }; -} - -template -struct ircd::db::where::logical_or -:ircd::db::where -{ - const where *a, *b; - - bool operator()(const tuple &t) const override - { - return (*a)(t) || (*b)(t); - } - - logical_or(const where &a, const where &b) - :a{&a} - ,b{&b} - {} -}; - -template -typename ircd::db::where::logical_or -ircd::db::operator||(const where &a, const where &b) -{ - return { a, b }; -} - -template -struct ircd::db::where::logical_not -:ircd::db::where -{ - const where *a; - - bool operator()(const tuple &t) const override - { - return !(*a)(t); - } - - logical_not(const where &a) - :a{&a} - {} -}; - -template -typename ircd::db::where::logical_not -ircd::db::operator!(const where &a) -{ - return { a }; -} - -template -struct ircd::db::where::test -:ircd::db::where -{ - using function = std::function; - - function closure; - - bool operator()(const tuple &t) const override - { - return closure(t); - } - - test(function closure) - :closure{std::move(closure)} - {} -}; - -template -struct ircd::db::where::noop -:ircd::db::where -{ - bool operator()(const tuple &) const override - { - return true; - } -}; diff --git a/ircd/db.cc b/ircd/db.cc index a803ed521..c71033091 100644 --- a/ircd/db.cc +++ b/ircd/db.cc @@ -4018,3 +4018,20 @@ ircd::db::value_required(const op &op) assert(0); return false; } + +ircd::string_view +ircd::db::reflect(const where &w) +{ + switch(w) + { + case where::noop: return "noop"; + case where::test: return "test"; + case where::equal: return "equal"; + case where::not_equal: return "not_equal"; + case where::logical_or: return "logical_or"; + case where::logical_and: return "logical_and"; + case where::logical_not: return "logical_not"; + } + + return "?????"; +}