2018-11-03 17:12:20 +01:00
/* Copyright (c) 2018 Albert S.
Permission is hereby granted , free of charge , to any person obtaining a copy
of this software and associated documentation files ( the " Software " ) , to deal
in the Software without restriction , including without limitation the rights
to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
copies of the Software , and to permit persons to whom the Software is
furnished to do so , subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software .
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE .
*/
# include <sqlite_modern_cpp/errors.h>
# include "pagedaosqlite.h"
# include "exceptions.h"
# include "sqlitequeryoption.h"
# include "../logger.h"
/* TODO: copied from C version mostly, review whether access to table other than page is ok */
2018-11-04 19:31:58 +01:00
bool PageDaoSqlite : : exists ( unsigned int id ) const
2018-11-03 17:12:20 +01:00
{
auto binder = * db < < " SELECT 1 from page WHERE id = ? " < < id ;
return execBool ( binder ) ;
}
bool PageDaoSqlite : : exists ( std : : string name ) const
{
auto binder = * db < < " SELECT 1 FROM page WHERE name = ? " < < name ;
return execBool ( binder ) ;
}
std : : optional < Page > PageDaoSqlite : : find ( std : : string name )
{
2018-11-05 10:48:58 +01:00
try
{
int pageid = fetchPageId ( name ) ;
return find ( pageid ) ;
}
catch ( const sqlite : : errors : : no_rows & e )
{
return { } ;
}
2018-11-03 17:12:20 +01:00
}
2018-11-04 19:31:58 +01:00
std : : optional < Page > PageDaoSqlite : : find ( unsigned int id )
2018-11-03 17:12:20 +01:00
{
Page result ;
2018-11-04 19:31:58 +01:00
result . pageid = id ;
2018-11-03 17:12:20 +01:00
try
{
auto ps = * db < < " SELECT name, lastrevision, visible FROM page WHERE id = ? " ;
ps < < id > > std : : tie ( result . name , result . current_revision , result . listed ) ;
}
catch ( const sqlite : : errors : : no_rows & e )
{
return { } ;
}
catch ( sqlite : : sqlite_exception & e )
{
throwFrom ( e ) ;
}
return result ;
}
void PageDaoSqlite : : deletePage ( std : : string page )
{
int pageId = this - > fetchPageId ( page ) ;
//TODO on delete cascade is better most certainly
try
{
* db < < " BEGIN; " ;
* db < < " DELETE FROM revision WHERE page = ?; " < < pageId ;
* db < < " DELETE FROM categorymember WHERE page = ?; " < < pageId ;
* db < < " DELETE FROM permissions WHERE page = ?; " < < pageId ;
* db < < " DELETE FROM page WHERE id =?; " < < pageId ;
* db < < " COMMIT; " ;
}
catch ( sqlite : : sqlite_exception & e )
{
throwFrom ( e ) ;
}
}
void PageDaoSqlite : : save ( const Page & page )
{
try
{
2018-11-04 19:31:58 +01:00
* db < < " INSERT OR REPLACE INTO page (id, name, lastrevision, visible) VALUES((SELECT id FROM page WHERE name = ? OR id = ?), ?, ?, ?) " < < page . name < < page . pageid < < page . name < < page . current_revision < < page . listed ;
2018-11-03 17:12:20 +01:00
}
catch ( sqlite : : sqlite_exception & e )
{
throwFrom ( e ) ;
}
}
std : : vector < std : : string > PageDaoSqlite : : getPageList ( QueryOption option )
{
std : : vector < std : : string > result ;
try
{
std : : string queryOption = SqliteQueryOption ( option ) . setOrderByColumn ( " lower(name) " ) . setVisibleColumnName ( " visible " ) . setPrependWhere ( true ) . build ( ) ;
std : : string query = " SELECT name FROM page " + queryOption ;
* db < < query > > [ & ] ( std : : string name )
{
result . push_back ( name ) ;
} ;
}
catch ( const sqlite : : errors : : no_rows & e )
{
return result ;
}
catch ( sqlite : : sqlite_exception & e )
{
throwFrom ( e ) ;
}
return result ;
}
std : : vector < std : : string > PageDaoSqlite : : fetchCategories ( std : : string pagename , QueryOption option )
{
std : : vector < std : : string > result ;
try
{
auto query = * db < < " SELECT name FROM categorymember INNNER JOIN category ON category = category.id WHERE page = (SELECT id FROM page WHERE name = ?) " < < pagename ;
query < < " AND " < < SqliteQueryOption ( option ) . setPrependWhere ( false ) . setOrderByColumn ( " name " ) . build ( ) ;
query > > [ & ] ( std : : string pagename ) { result . push_back ( pagename ) ; } ;
}
catch ( const sqlite : : exceptions : : no_rows & e )
{
return result ;
}
catch ( sqlite : : sqlite_exception & e )
{
throwFrom ( e ) ;
}
return result ;
}
std : : vector < SearchResult > PageDaoSqlite : : search ( std : : string name , QueryOption option )
{
std : : vector < SearchResult > result ;
try
{
std : : string qo = SqliteQueryOption ( option ) . setPrependWhere ( false ) . setOrderByColumn ( " rank " ) . build ( ) ;
//TODO: what is passed here, simple gets thrown to the MATCH operator without escaping or anything and this is suboptimal
auto query = * db < < " SELECT page.name FROM search INNER JOIN page ON search.page = page.id WHERE search MATCH ? " < < name ;
query > > [ & ] ( std : : string pagename ) {
SearchResult sresult ;
sresult . pagename = pagename ;
sresult . query = name ;
result . push_back ( sresult ) ;
} ;
}
catch ( const sqlite : : exceptions : : no_rows & e )
{
return result ;
}
catch ( sqlite : : sqlite_exception & e )
{
throwFrom ( e ) ;
}
return result ;
}
void PageDaoSqlite : : setCategories ( std : : string pagename , const std : : vector < std : : string > & catnames )
{
try
{
int pageid = fetchPageId ( pagename ) ;
* db < < " savepoint setcategories; " ;
* db < < " DELETE FROM categorymember WHERE page = ? " < < pageid ;
for ( const std : : string & cat : catnames )
{
* db < < " INSERT OR IGNORE INTO category (id, name) VALUES( (SELECT id FROM category WHERE lower(name) = lower(?)), lower(?)) " < < cat < < cat ;
* db < < " INSERT INTO categorymember (category, page) VALUES ( (SELECT ID FROM category WHERE lower(name) = lower(?)), ?) " < < cat < < pageid ;
}
* db < < " release setcategories; " ;
}
catch ( sqlite : : sqlite_exception & e )
{
throwFrom ( e ) ;
}
}
int PageDaoSqlite : : fetchPageId ( std : : string pagename )
{
auto binder = * db < < " SELECT id FROM page WHERE name = ? " < < pagename ;
return execInt ( binder ) ;
}