LCOV - code coverage report
Current view: top level - core/db - SPDbContinueToken.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 108 132 81.8 %
Date: 2024-05-12 00:16:13 Functions: 22 28 78.6 %

          Line data    Source code
       1             : /**
       2             : Copyright (c) 2019-2022 Roman Katuntsev <sbkarr@stappler.org>
       3             : Copyright (c) 2023-2024 Stappler LLC <admin@stappler.dev>
       4             : 
       5             : Permission is hereby granted, free of charge, to any person obtaining a copy
       6             : of this software and associated documentation files (the "Software"), to deal
       7             : in the Software without restriction, including without limitation the rights
       8             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       9             : copies of the Software, and to permit persons to whom the Software is
      10             : furnished to do so, subject to the following conditions:
      11             : 
      12             : The above copyright notice and this permission notice shall be included in
      13             : all copies or substantial portions of the Software.
      14             : 
      15             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      18             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      20             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      21             : THE SOFTWARE.
      22             : **/
      23             : 
      24             : #include "SPDbContinueToken.h"
      25             : #include "SPDbScheme.h"
      26             : 
      27             : namespace STAPPLER_VERSIONIZED stappler::db {
      28             : 
      29         150 : ContinueToken::ContinueToken(const StringView &field, size_t count, bool reverse)
      30         150 : : field(field.str<Interface>()), count(count), flags(Initial) {
      31         150 :         if (reverse) {
      32          75 :                 flags |= Reverse | Inverted;
      33             :         }
      34         150 : }
      35             : 
      36         300 : ContinueToken::ContinueToken(const StringView &str) {
      37         300 :         auto bytes = stappler::base64::decode<Interface>(str);
      38         300 :         auto d = data::read<Interface, typeof(bytes)>(bytes);
      39         300 :         if (d.isArray() && d.size() == 6) {
      40         300 :                 field = d.getString(0);
      41         300 :                 initVec = d.getValue(1);
      42         300 :                 count = (size_t)d.getInteger(2);
      43         300 :                 fetched = (size_t)d.getInteger(3);
      44         300 :                 total = (size_t)d.getInteger(4);
      45         300 :                 flags |= Flags(d.getInteger(5));
      46             :         }
      47         300 : }
      48             : 
      49         425 : bool ContinueToken::hasPrev() const {
      50         425 :         return hasFlag(Flags::Inverted) ? hasNextImpl() : hasPrevImpl();
      51             : }
      52         425 : bool ContinueToken::hasNext() const {
      53         425 :         return hasFlag(Flags::Inverted) ? hasPrevImpl() : hasNextImpl();
      54             : }
      55             : 
      56         375 : bool ContinueToken::isInit() const {
      57         375 :         return _init;
      58             : }
      59             : 
      60          75 : String ContinueToken::encode() const {
      61         750 :         return stappler::base64url::encode<Interface>(stappler::data::write<Interface>(Value({
      62          75 :                 Value(field),
      63          75 :                 Value(initVec),
      64          75 :                 Value(count),
      65          75 :                 Value(fetched),
      66          75 :                 Value(total),
      67          75 :                 Value(stappler::toInt(flags)),
      68         675 :         }), EncodeFormat::Cbor));
      69             : }
      70             : 
      71         250 : String ContinueToken::encodeNext() const {
      72         250 :         return hasFlag(Flags::Inverted) ? encodePrevImpl() : encodeNextImpl();
      73             : }
      74             : 
      75         250 : String ContinueToken::encodePrev() const {
      76         250 :         return hasFlag(Flags::Inverted) ? encodeNextImpl() : encodePrevImpl();
      77             : }
      78             : 
      79         425 : size_t ContinueToken::getStart() const {
      80         425 :         return hasFlag(Flags::Inverted) ? (getTotal() + 1 - fetched - getNumResults()) : (fetched + 1);
      81             : }
      82         425 : size_t ContinueToken::getEnd() const {
      83         425 :         return hasFlag(Flags::Inverted) ? std::min(total, getTotal() - fetched) : std::min(total, fetched + getNumResults());
      84             : }
      85         875 : size_t ContinueToken::getTotal() const {
      86         875 :         return total;
      87             : }
      88         375 : size_t ContinueToken::getCount() const {
      89         375 :         return count;
      90             : }
      91           0 : size_t ContinueToken::getFetched() const {
      92           0 :         return fetched;
      93             : }
      94         375 : StringView ContinueToken::getField() const {
      95         375 :         return field;
      96             : }
      97             : 
      98         425 : size_t ContinueToken::getNumResults() const {
      99         425 :         return _numResults;
     100             : }
     101             : 
     102        4450 : bool ContinueToken::hasFlag(Flags fl) const {
     103        4450 :         return (flags & fl) != Flags::None;
     104             : }
     105             : 
     106           0 : void ContinueToken::setFlag(Flags fl) {
     107           0 :         flags |= fl;
     108           0 : }
     109           0 : void ContinueToken::unsetFlag(Flags fl) {
     110           0 :         flags &= (~fl);
     111           0 : }
     112             : 
     113           0 : const Value &ContinueToken::getFirstVec() const {
     114           0 :         return firstVec;
     115             : }
     116           0 : const Value &ContinueToken::getLastVec() const {
     117           0 :         return lastVec;
     118             : }
     119             : 
     120         425 : bool ContinueToken::hasPrevImpl() const {
     121         425 :         return _init && fetched != 0;
     122             : }
     123             : 
     124         425 : bool ContinueToken::hasNextImpl() const {
     125         425 :         return _init && fetched + _numResults < total;
     126             : }
     127             : 
     128         250 : String ContinueToken::encodeNextImpl() const {
     129         250 :         Flags f = Flags::None;
     130         250 :         if (hasFlag(Flags::Inverted)) { f |= Flags::Inverted; }
     131        2500 :         return stappler::base64url::encode<Interface>(stappler::data::write<Interface>(Value({
     132         250 :                 Value(field),
     133         250 :                 Value(lastVec),
     134         250 :                 Value(count),
     135         250 :                 Value(fetched + _numResults),
     136         250 :                 Value(total),
     137             :                 Value(stappler::toInt(f))
     138        2250 :         }), EncodeFormat::Cbor));
     139             : }
     140             : 
     141         250 : String ContinueToken::encodePrevImpl() const {
     142         250 :         Flags f = Flags::Reverse;
     143         250 :         if (hasFlag(Flags::Inverted)) { f |= Flags::Inverted; }
     144        2500 :         return stappler::base64url::encode<Interface>(stappler::data::write<Interface>(Value({
     145         250 :                 Value(field),
     146         250 :                 Value(firstVec),
     147         250 :                 Value(count),
     148         250 :                 Value(fetched),
     149         250 :                 Value(total),
     150             :                 Value(stappler::toInt(f))
     151        2250 :         }), EncodeFormat::Cbor));
     152             : }
     153             : 
     154         425 : Value ContinueToken::perform(const Scheme &scheme, const Transaction &t, Query &q) {
     155         425 :         if (field != "__oid" && !scheme.getField(field)) {
     156           0 :                 return Value();
     157             :         }
     158             : 
     159         425 :         q.select(field, db::Comparation::IsNotNull, Value(true));
     160         425 :         if (total == 0) {
     161         150 :                 total = scheme.count(t, q);
     162         150 :                 if (hasFlag(Flags::Reverse) && !fetched) {
     163          75 :                         fetched = total;
     164             :                 }
     165             :         }
     166             : 
     167         425 :         if (total == 0) {
     168           0 :                 _init = true;
     169           0 :                 return Value();
     170             :         }
     171             : 
     172         425 :         q.softLimit(field, hasFlag(Flags::Reverse) ? Ordering::Descending : Ordering::Ascending, count, Value(initVec));
     173             : 
     174         425 :         auto d = scheme.select(t, q);
     175         425 :         if (d.isArray()) {
     176         425 :                 _numResults = d.size();
     177         425 :                 if (hasFlag(Flags::Reverse)) {
     178         225 :                         fetched -= (std::min(fetched, _numResults));
     179         225 :                         firstVec = d.asArray().back().getValue(field);
     180         225 :                         lastVec = d.asArray().front().getValue(field);
     181             :                 } else {
     182         200 :                         firstVec = d.asArray().front().getValue(field);
     183         200 :                         lastVec = d.asArray().back().getValue(field);
     184             :                 }
     185         425 :                 _init = true;
     186             :         }
     187             : 
     188         425 :         return d;
     189         425 : }
     190             : 
     191         375 : Value ContinueToken::perform(const Scheme &scheme, const Transaction &t, Query &q, Ordering ord) {
     192         375 :         auto rev = hasFlag(Flags::Reverse);
     193         375 :         if (auto d = perform(scheme, t, q)) {
     194         375 :                 if ((ord == Ordering::Ascending && rev) || (ord == Ordering::Descending && !rev)) {
     195           0 :                         std::reverse(d.asArray().begin(), d.asArray().end());
     196             :                 }
     197         375 :                 return d;
     198         375 :         }
     199           0 :         return Value();
     200             : }
     201             : 
     202           0 : Value ContinueToken::performOrdered(const Scheme &scheme, const Transaction &t, Query &q) {
     203           0 :         if (!q.getOrderField().empty()) {
     204           0 :                 field = q.getOrderField();
     205             :         }
     206             : 
     207           0 :         if (q.getOrdering() == db::Ordering::Descending) {
     208           0 :                 setFlag(Flags::Inverted);
     209             :         } else {
     210           0 :                 unsetFlag(Flags::Inverted);
     211             :         }
     212             : 
     213           0 :         return perform(scheme, t, q, q.getOrdering());
     214             : }
     215             : 
     216          25 : void ContinueToken::refresh(const Scheme &scheme, const Transaction &t, Query &q) {
     217          25 :         q.select(field, db::Comparation::IsNotNull, Value(true));
     218          25 :         auto newTotal = scheme.count(t, q);
     219             : 
     220          25 :         q.select(field, db::Comparation::LessThen, initVec);
     221          25 :         auto newFetched = scheme.count(t, q);
     222             : 
     223          25 :         total = newTotal;
     224          25 :         fetched = newFetched;
     225          25 : }
     226             : 
     227             : }

Generated by: LCOV version 1.14