LCOV - code coverage report
Current view: top level - core/sql - SPSqlSelect.hpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 150 161 93.2 %
Date: 2024-05-12 00:16:13 Functions: 59 81 72.8 %

          Line data    Source code
       1             : /**
       2             : Copyright (c) 2017-2022 Roman Katuntsev <sbkarr@stappler.org>
       3             : Copyright (c) 2023 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             : // Excluded from documentation/codegen tool
      25             : ///@ SP_EXCLUDE
      26             : 
      27             : #ifndef STAPPLER_SQL_SPSQLSELECT_HPP_
      28             : #define STAPPLER_SQL_SPSQLSELECT_HPP_
      29             : 
      30             : #include "SPSql.h"
      31             : 
      32             : namespace STAPPLER_VERSIONIZED stappler::sql {
      33             : 
      34             : template <typename Binder, typename Interface>
      35          50 : auto Query<Binder, Interface>::Select::all() -> Select & {
      36          50 :         if (this->state == State::None) { this->state = State::Some; } else { this->query->stream << ","; }
      37          50 :         this->query->stream << " *";
      38          50 :         return *this;
      39             : }
      40             : 
      41             : template <typename Binder, typename Interface>
      42         375 : auto Query<Binder, Interface>::Select::count() -> Select & {
      43         375 :         if (this->state == State::None) { this->state = State::Some; } else { this->query->stream << ","; }
      44         375 :         this->query->stream << " COUNT(*)";
      45         375 :         return *this;
      46             : }
      47             : 
      48             : template <typename Binder, typename Interface>
      49         575 : auto Query<Binder, Interface>::Select::count(const String &alias) -> Select & {
      50         575 :         if (this->state == State::None) { this->state = State::Some; } else { this->query->stream << ","; }
      51         575 :         this->query->stream << " COUNT(*) AS \"" << alias << "\"";
      52         575 :         return *this;
      53             : }
      54             : 
      55             : template <typename Binder, typename Interface>
      56             : template <typename Clause>
      57             : template <typename ...Args>
      58        1275 : auto Query<Binder, Interface>::FieldsClause<Clause>::fields(const Field &f, Args && ... args) -> Clause & {
      59        1275 :         Expand<Clause>::fields((Clause &)*this, f, std::forward<Args>(args)...);
      60        1275 :         return (Clause &)*this;
      61             : }
      62             : 
      63             : template <typename Binder, typename Interface>
      64             : template <typename Clause>
      65       62275 : auto Query<Binder, Interface>::FieldsClause<Clause>::field(const Field &f) -> Clause & {
      66       62275 :         switch (this->state) {
      67       14975 :         case State::None:
      68       14975 :                 this->query->stream << " ";
      69       14975 :                 this->state = State::Some;
      70       14975 :                 break;
      71        4400 :         case State::Init:
      72        4400 :                 this->query->stream << "(";
      73        4400 :                 this->state = State::Some;
      74        4400 :                 break;
      75       42900 :         case State::Some:
      76       42900 :                 this->query->stream << ", ";
      77       42900 :                 break;
      78             :         }
      79       62275 :         this->query->writeBind(f);
      80       62275 :         return (Clause &)*this;
      81             : }
      82             : 
      83             : template <typename Binder, typename Interface>
      84             : template <typename Clause>
      85        1075 : auto Query<Binder, Interface>::FieldsClause<Clause>::aggregate(const StringView &func, const Field &f) -> Clause & {
      86        1075 :         switch (this->state) {
      87        1000 :         case State::None:
      88        1000 :                 this->query->stream << " ";
      89        1000 :                 this->state = State::Some;
      90        1000 :                 break;
      91           0 :         case State::Init:
      92           0 :                 this->query->stream << "(";
      93           0 :                 this->state = State::Some;
      94           0 :                 break;
      95          75 :         case State::Some:
      96          75 :                 this->query->stream << ", ";
      97          75 :                 break;
      98             :         }
      99        1075 :         this->query->writeBind(func, f);
     100        1075 :         return (Clause &)*this;
     101             : }
     102             : 
     103             : template <typename Binder, typename Interface>
     104        1125 : auto Query<Binder, Interface>::Select::from() -> Query<Binder, Interface>::SelectFrom {
     105        1125 :         if (this->state == State::None) {
     106        1125 :                 this->query->stream << " *";
     107             :         }
     108        1125 :         this->query->stream << " FROM";
     109        1125 :         return SelectFrom{this->query};
     110             : }
     111             : 
     112             : template <typename Binder, typename Interface>
     113       12500 : auto Query<Binder, Interface>::Select::from(const Field &field) -> SelectFrom {
     114       12500 :         if (this->state == State::None) {
     115        1425 :                 this->query->stream << " *";
     116             :         }
     117       12500 :         this->query->stream << " FROM " << field.name;
     118       12500 :         this->query->target = field.name;
     119       12500 :         if (!field.alias.empty()) {
     120         725 :                 this->query->stream << " " << field.alias;
     121             :         }
     122       12500 :         return SelectFrom(this->query, State::Some);
     123             : }
     124             : 
     125             : template <typename Binder, typename Interface>
     126             : template <typename ... Args>
     127        1125 : auto Query<Binder, Interface>::Select::from(const Field &field, Args && ... args) -> SelectFrom {
     128        1125 :         auto f = from();
     129        1125 :         Expand<SelectFrom>::from(f, field, forward<Args>(args)...);
     130        1125 :         return f;
     131             : }
     132             : 
     133             : template <typename Binder, typename Interface>
     134        2375 : auto Query<Binder, Interface>::SelectFrom::from(const Field &field) -> SelectFrom & {
     135        2375 :         if (this->state == State::None) { this->state = State::Some; } else { this->query->stream << ","; }
     136        2375 :         this->query->stream << " " << field.name;
     137        2375 :         if (this->query->target.empty()) {
     138           0 :                 this->query->target = field.name;
     139             :         }
     140        2375 :         if (!field.alias.empty()) {
     141         100 :                 this->query->stream << " \"" << field.alias << "\"";
     142             :         }
     143        2375 :         return *this;
     144             : }
     145             : 
     146             : template <typename Binder, typename Interface>
     147             : template <typename ... Args>
     148             : auto Query<Binder, Interface>::SelectFrom::from(const Field &field, Args && ... args) -> SelectFrom & {
     149             :         Expand<SelectFrom>::from(*this, forward<Args>(args)...);
     150             :         return *this;
     151             : }
     152             : 
     153             : template <typename Binder, typename Interface>
     154             : template <typename Callback>
     155        1425 : auto Query<Binder, Interface>::SelectFrom::innerJoinOn(const StringView &s, const Callback &cb) -> SelectFrom & {
     156        1425 :         if (this->state == State::Some) {
     157        1425 :                 this->query->stream << " INNER JOIN " << s << " ON(";
     158        1425 :                 WhereBegin tmp(this->query);
     159        1425 :                 cb(tmp);
     160        1425 :                 this->query->stream << ")";
     161             :         }
     162        1425 :         return *this;
     163             : }
     164             : 
     165             : template <typename Binder, typename Interface>
     166             : template <typename Callback>
     167             : auto Query<Binder, Interface>::SelectFrom::leftJoinOn(const StringView &s, const Callback &cb) -> SelectFrom & {
     168             :         if (this->state == State::Some) {
     169             :                 this->query->stream << " LEFT OUTER JOIN " << s << " ON(";
     170             :                 WhereBegin tmp(this->query);
     171             :                 cb(tmp);
     172             :                 this->query->stream << ")";
     173             :         }
     174             :         return *this;
     175             : }
     176             : 
     177             : template <typename Binder, typename Interface>
     178             : template <typename Callback>
     179         175 : auto Query<Binder, Interface>::SelectFrom::rightJoinOn(const StringView &s, const Callback &cb) -> SelectFrom & {
     180         175 :         if (this->state == State::Some) {
     181         175 :                 this->query->stream << " RIGHT OUTER JOIN " << s << " ON(";
     182         175 :                 WhereBegin tmp(this->query);
     183         175 :                 cb(tmp);
     184         175 :                 this->query->stream << ")";
     185             :         }
     186         175 :         return *this;
     187             : }
     188             : 
     189             : template <typename Binder, typename Interface>
     190             : template <typename Callback>
     191             : auto Query<Binder, Interface>::SelectFrom::fullJoinOn(const StringView &s, const Callback &cb) -> SelectFrom & {
     192             :         if (this->state == State::Some) {
     193             :                 this->query->stream << " FULL OUTER JOIN " << s << " ON(";
     194             :                 WhereBegin tmp(this->query);
     195             :                 cb(tmp);
     196             :                 this->query->stream << ")";
     197             :         }
     198             :         return *this;
     199             : }
     200             : 
     201             : template <typename Binder, typename Interface>
     202             : template <typename ... Args>
     203        2425 : auto Query<Binder, Interface>::SelectFrom::where(Args && ... args) -> SelectWhere {
     204        2425 :         this->query->stream << " WHERE";
     205        2425 :         SelectWhere q(this->query);
     206        2425 :         q.where(sql::Operator::And, std::forward<Args>(args)...);
     207        2425 :         return q;
     208             : }
     209             : 
     210             : template <typename Binder, typename Interface>
     211        7500 : auto Query<Binder, Interface>::SelectFrom::where() -> SelectWhere {
     212        7500 :         this->query->stream << " WHERE";
     213        7500 :         return SelectWhere(this->query);
     214             : }
     215             : 
     216             : template <typename Binder, typename Interface>
     217             : auto Query<Binder, Interface>::SelectFrom::group(const Field &f) -> SelectGroup {
     218             :         this->query->stream << " GROUP BY ";
     219             :         auto g = SelectGroup(this->query);
     220             :         g.field(f);
     221             :         return g;
     222             : }
     223             : 
     224             : template <typename Binder, typename Interface>
     225        1375 : inline auto Query_writeOrderSt(typename Interface::StringStreamType &stream, Query<Binder, Interface> &query, Ordering ord, const typename Query<Binder, Interface>::Field &field, Nulls n) {
     226        1375 :         stream << " ORDER BY ";
     227        1375 :         query.writeBind(field, false);
     228        1375 :         switch (ord) {
     229         625 :         case Ordering::Ascending: stream << " ASC"; break;
     230         750 :         case Ordering::Descending: stream << " DESC"; break;
     231             :         }
     232             : 
     233        1375 :         switch (n) {
     234         775 :         case Nulls::None: break;
     235           0 :         case Nulls::First: stream << " NULLS FIRST"; break;
     236         600 :         case Nulls::Last: stream << " NULLS LAST"; break;
     237             :         }
     238        1375 : }
     239             : 
     240             : template <typename Binder, typename Interface>
     241        1175 : auto Query<Binder, Interface>::SelectFrom::order(Ordering ord, const Field &field, Nulls n) -> SelectOrder {
     242        1175 :         Query_writeOrderSt<Binder>(this->query->stream, *this->query, ord, field, n);
     243        1175 :         return SelectOrder(this->query);
     244             : }
     245             : 
     246             : template <typename Binder, typename Interface>
     247        1925 : void Query<Binder, Interface>::SelectFrom::forUpdate() {
     248        1925 :         switch (this->query->profile) {
     249         775 :         case Profile::Postgres: this->query->stream << " FOR UPDATE"; break;
     250        1150 :         case Profile::Sqlite: break;
     251             :         }
     252        1925 : }
     253             : 
     254             : template <typename Binder, typename Interface>
     255             : template <typename ...Args>
     256             : auto Query<Binder, Interface>::SelectGroup::fields(const Field &f, Args && ... args) -> SelectGroup & {
     257             :         Expand<SelectGroup>::fields(*this, f, std::forward<Args>(args)...);
     258             :         return *this;
     259             : }
     260             : 
     261             : template <typename Binder, typename Interface>
     262         175 : auto Query<Binder, Interface>::SelectGroup::field(const Field &f) -> SelectGroup & {
     263         175 :         switch (this->state) {
     264         125 :         case State::None:
     265         125 :                 this->query->stream << " ";
     266         125 :                 this->state = State::Some;
     267         125 :                 break;
     268          50 :         case State::Some:
     269          50 :                 this->query->stream << ", ";
     270          50 :                 break;
     271           0 :         default:
     272           0 :                 break;
     273             :         }
     274         175 :         this->query->writeBind(f, false);
     275         175 :         return *this;
     276             : }
     277             : 
     278             : template <typename Binder, typename Interface>
     279          75 : auto Query<Binder, Interface>::SelectGroup::order(Ordering ord, const Field &field, Nulls n) -> SelectOrder {
     280          75 :         Query_writeOrderSt<Binder>(this->query->stream, *this->query, ord, field, n);
     281          75 :         return SelectOrder(this->query);
     282             : }
     283             : 
     284             : template <typename Binder, typename Interface>
     285         125 : auto Query<Binder, Interface>::SelectWhere::group(const Field &f) -> SelectGroup {
     286         125 :         this->query->stream << " GROUP BY ";
     287         125 :         auto g = SelectGroup(this->query);
     288         125 :         g.field(f);
     289         125 :         return g;
     290             : }
     291             : 
     292             : template <typename Binder, typename Interface>
     293         125 : auto Query<Binder, Interface>::SelectWhere::order(Ordering ord, const Field &field, Nulls n) -> SelectOrder {
     294         125 :         Query_writeOrderSt<Binder>(this->query->stream, *this->query, ord, field, n);
     295         125 :         return SelectOrder(this->query);
     296             : }
     297             : 
     298             : template <typename Binder, typename Interface>
     299             : void Query<Binder, Interface>::SelectWhere::forUpdate() {
     300             :         switch (this->query->profile) {
     301             :         case Profile::Postgres: this->query->stream << " FOR UPDATE"; break;
     302             :         case Profile::Sqlite: break;
     303             :         }
     304             : }
     305             : 
     306             : template <typename Binder, typename Interface>
     307          75 : auto Query<Binder, Interface>::SelectOrder::limit(size_t limit, size_t offset) -> SelectPost {
     308          75 :         this->query->stream << " LIMIT " << limit << " OFFSET " << offset;
     309          75 :         return SelectPost(this->query);
     310             : }
     311             : 
     312             : template <typename Binder, typename Interface>
     313         825 : auto Query<Binder, Interface>::SelectOrder::limit(size_t limit) -> SelectPost  {
     314         825 :         this->query->stream << " LIMIT " << limit;
     315         825 :         return SelectPost(this->query);
     316             : }
     317             : 
     318             : template <typename Binder, typename Interface>
     319           0 : auto Query<Binder, Interface>::SelectOrder::offset(size_t offset) -> SelectPost {
     320           0 :         this->query->stream << " OFFSET " << offset;
     321           0 :         return SelectPost(this->query);
     322             : }
     323             : 
     324             : template <typename Binder, typename Interface>
     325             : void Query<Binder, Interface>::SelectOrder::forUpdate() {
     326             :         switch (this->query->profile) {
     327             :         case Profile::Postgres: this->query->stream << " FOR UPDATE"; break;
     328             :         case Profile::Sqlite: break;
     329             :         }
     330             : }
     331             : 
     332             : template <typename Binder, typename Interface>
     333             : void Query<Binder, Interface>::SelectPost::forUpdate() {
     334             :         switch (this->query->profile) {
     335             :         case Profile::Postgres: this->query->stream << " FOR UPDATE"; break;
     336             :         case Profile::Sqlite: break;
     337             :         }
     338             : }
     339             : 
     340             : template <typename Binder, typename Interface>
     341             : template <typename ... Args>
     342         375 : auto Query<Binder, Interface>::select(const Field &f, Args && ... args) -> Select {
     343         375 :         auto s = select();
     344         375 :         s.fields(f, forward<Args>(args)...);
     345         375 :         return s;
     346             : }
     347             : 
     348             : template <typename Binder, typename Interface>
     349             : template <typename ... Args>
     350         125 : auto Query<Binder, Interface>::select(Distinct d, const Field &f, Args && ... args) -> Select {
     351         125 :         auto s = select(d);
     352         125 :         s.fields(f, forward<Args>(args)...);
     353         125 :         return s;
     354             : }
     355             : 
     356             : template <typename Binder, typename Interface>
     357       13625 : auto Query<Binder, Interface>::select(Distinct d) -> Select {
     358       13625 :         stream << "SELECT";
     359       13625 :         switch (d) {
     360         125 :         case Distinct::Distinct:
     361         125 :                 stream << " DISTINCT";
     362         125 :                 break;
     363       13500 :         default:
     364       13500 :                 break;
     365             :         }
     366       13625 :         return Select(this);
     367             : }
     368             : 
     369             : }
     370             : 
     371             : #endif /* STAPPLER_SQL_SPSQLSELECT_HPP_ */

Generated by: LCOV version 1.14