added models Thread and ThreadFiles in thread plugin

This commit is contained in:
Tomasz Sowa 2021-05-21 23:06:48 +02:00
parent 86ef2529b1
commit b2cffa39e1
12 changed files with 478 additions and 162 deletions

View File

@ -105,13 +105,19 @@ void CreateThread::MakePost()
if( functions->CheckAbuse() ) if( functions->CheckAbuse() )
return; return;
thread.set_connector(model_connector);
thread.clear();
cur->request->status = system->AddFile(cur->request->item) ? WINIX_ERR_OK : WINIX_ERR_PERMISSION_DENIED; cur->request->status = system->AddFile(cur->request->item) ? WINIX_ERR_OK : WINIX_ERR_PERMISSION_DENIED;
if( cur->request->status == WINIX_ERR_OK ) if( cur->request->status == WINIX_ERR_OK )
{ {
thread.Clear();
thread.file_id = cur->request->item.id; thread.file_id = cur->request->item.id;
cur->request->status = tdb->AddThread(thread); thread.last_item.id = cur->request->item.id;
thread.set_has_primary_key_set(true);
if( !thread.insert() )
cur->request->status = WINIX_ERR_PERMISSION_DENIED;
} }
if( cur->request->status == WINIX_ERR_OK ) if( cur->request->status == WINIX_ERR_OK )

View File

@ -79,19 +79,25 @@ return true;
void FunThread::PrepareThread(long file_id) void FunThread::PrepareThread(long file_id)
{ {
thread_info->Clear(); thread_info->Clear();
cur->request->status = tdb->GetAnswers(file_id, id_tab); //cur->request->status = tdb->GetAnswers(file_id, id_tab);
morm::Finder<ThreadFiles> finder_answers(model_connector);
std::vector<ThreadFiles> answers = finder_answers.
select().
where().
eq(L"file_id", file_id).
get_vector();
id_tab.resize(answers.size());
for(size_t i = 0 ; i < answers.size() ; ++i)
{
id_tab[i] = answers[i].answer_id;
}
if( !id_tab.empty() ) if( !id_tab.empty() )
{ {
// DbItemQuery iq;
//
// if( system->mounts.pmount->IsArg(thread_info->mount_par_thread, L"sort_desc") )
// iq.sort_date_asc = false; // sort_index_asc we are ignoring
//
// iq.WhereIdIn(id_tab);
// iq.WhereType(Item::file);
// iq.WhereFileType(WINIX_ITEM_FILETYPE_NONE);
morm::Finder<Item> finder(model_connector); morm::Finder<Item> finder(model_connector);
thread_info->item_tab = finder. thread_info->item_tab = finder.

View File

@ -38,6 +38,8 @@
#include "functions/functionbase.h" #include "functions/functionbase.h"
#include "tdb.h" #include "tdb.h"
#include "threadinfo.h" #include "threadinfo.h"
#include "threadfiles.h"
namespace Winix namespace Winix
{ {
@ -63,6 +65,7 @@ private:
TDb * tdb; TDb * tdb;
ThreadInfo * thread_info; ThreadInfo * thread_info;
std::vector<ThreadFiles> answers;
std::vector<long> id_tab; std::vector<long> id_tab;
}; };

View File

@ -112,11 +112,13 @@ void Reply::MakePost()
// !! jak bedzie dostepne assert // !! jak bedzie dostepne assert
// ASSERT(files_dir) // ASSERT(files_dir)
if( tdb->GetThread(cur->request->item.id, thread) != WINIX_ERR_OK ) thread = Thread::get_thread(model_connector, cur->request->item.id);
if( !thread.found() )
{ {
thread.Clear(); thread.clear();
thread.file_id = cur->request->item.id; thread.file_id = cur->request->item.id;
tdb->AddThread(thread); thread.insert();
} }
answer.Clear(); answer.Clear();

View File

@ -98,21 +98,6 @@ bool ShowThreads::Sort::operator()(const Item * item1, const Item * item2)
void ShowThreads::ReadFiles() void ShowThreads::ReadFiles()
{ {
// reading files
// DbItemQuery iq;
// iq.SetAll(false, false);
// iq.sel_url = true;
// iq.sel_subject = true;
// iq.sel_date = true;
// iq.sel_user_id = true;
// iq.sel_group_id = true;
// iq.sel_guest_name = true;
// iq.sel_privileges = true;
// iq.sel_date = true;
// iq.WhereParentId(cur->request->dir_tab.back()->id);
// iq.WhereType(Item::file);
// iq.WhereFileType(WINIX_ITEM_FILETYPE_NONE);
morm::Finder<Item> finder(model_connector); morm::Finder<Item> finder(model_connector);
thread_info->item_tab = finder. thread_info->item_tab = finder.
@ -123,7 +108,6 @@ void ShowThreads::ReadFiles()
eq(L"content", L"file_type", WINIX_ITEM_FILETYPE_NONE). eq(L"content", L"file_type", WINIX_ITEM_FILETYPE_NONE).
get_vector(); get_vector();
//db->GetItems(thread_info->item_tab, iq);
system->CheckAccessToItems(thread_info->item_tab); system->CheckAccessToItems(thread_info->item_tab);
} }
@ -160,7 +144,7 @@ void ShowThreads::ReadThreads()
for(size_t i=0 ; i<thread_info->item_sort_tab.size() ; ++i) for(size_t i=0 ; i<thread_info->item_sort_tab.size() ; ++i)
file_id_tab[i] = thread_info->item_sort_tab[i]->id; file_id_tab[i] = thread_info->item_sort_tab[i]->id;
tdb->GetThreads(file_id_tab, thread_info->thread_tab); thread_info->thread_tab = Thread::get_threads(model_connector, file_id_tab);
} }

View File

@ -5,7 +5,7 @@
*/ */
/* /*
* Copyright (c) 2010-2014, Tomasz Sowa * Copyright (c) 2010-2021, Tomasz Sowa
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -45,18 +45,18 @@ namespace Thread
Error TDb::AddThread(const Thread & thread) //Error TDb::AddThread(const Thread & thread)
{ //{
query.Clear(); // query.Clear();
query << R("insert into plugins.thread (file_id, replies, last_item, closed) values (") // query << R("insert into plugins.thread (file_id, replies, last_item, closed) values (")
<< thread.file_id // << thread.file_id
<< thread.replies // << thread.replies
<< thread.last_item_id // << thread.last_item_id
<< (thread.closed ? 1 : 0 ) // << (thread.closed ? 1 : 0 )
<< R(");"); // << R(");");
//
return DoCommand(query); //return DoCommand(query);
} //}
@ -65,10 +65,10 @@ void TDb::SetThreadColumns(PGresult * r)
cfile_id = AssertColumn(r, "file_id"); cfile_id = AssertColumn(r, "file_id");
creplies = AssertColumn(r, "replies"); creplies = AssertColumn(r, "replies");
cclosed = AssertColumn(r, "closed"); cclosed = AssertColumn(r, "closed");
clast_item = AssertColumn(r, "last_item"); // clast_item = AssertColumn(r, "last_item");
cdate_modification = AssertColumn(r, "date_modification"); // cdate_modification = AssertColumn(r, "date_modification");
cuser_id = AssertColumn(r, "user_id"); // cuser_id = AssertColumn(r, "user_id");
cguest = AssertColumn(r, "guest_name"); // cguest = AssertColumn(r, "guest_name");
} }
@ -77,95 +77,95 @@ void TDb::SetThread(PGresult * r, int col, Thread & thread)
thread.file_id = AssertValueLong(r, col, cfile_id); thread.file_id = AssertValueLong(r, col, cfile_id);
thread.replies = AssertValueLong(r, col, creplies); thread.replies = AssertValueLong(r, col, creplies);
thread.closed = AssertValueBool(r, col, cclosed); thread.closed = AssertValueBool(r, col, cclosed);
thread.last_item_id = AssertValueLong(r, col, clast_item); //thread.last_item_id = AssertValueLong(r, col, clast_item);
thread.last_item_date_modification = AssertValueDate(r, col, cdate_modification); //thread.last_item_date_modification = AssertValueDate(r, col, cdate_modification);
thread.last_item_user_id = AssertValueLong(r, col, cuser_id); //thread.last_item_user_id = AssertValueLong(r, col, cuser_id);
AssertValueWide(r, col, cguest, thread.last_item_guest_name); //AssertValueWide(r, col, cguest, thread.last_item_guest_name);
} }
Error TDb::GetThread(long file_id, Thread & thread) //Error TDb::GetThread(long file_id, Thread & thread)
{ //{
PGresult * r = 0; // PGresult * r = 0;
Error status = WINIX_ERR_OK; // Error status = WINIX_ERR_OK;
//
try // try
{ // {
query.Clear(); // query.Clear();
query << R("select thread.file_id, thread.replies, thread.closed, thread.last_item, " // query << R("select thread.file_id, thread.replies, thread.closed, thread.last_item, "
"item.date_modification, item.user_id, item.guest_name " // "item.date_modification, item.user_id, item.guest_name "
"from plugins.thread left join core.item on thread.last_item = item.id " // "from plugins.thread left join core.item on thread.last_item = item.id "
"where thread.file_id = ") << file_id << R(";"); // "where thread.file_id = ") << file_id << R(";");
//
r = AssertQuery(query); // r = AssertQuery(query);
AssertResult(r, PGRES_TUPLES_OK); // AssertResult(r, PGRES_TUPLES_OK);
//
int rows = Rows(r); // int rows = Rows(r);
//
if( rows > 1 ) // if( rows > 1 )
log << log1 << "ThreadDb: there is more than one thread with file_id: " << file_id << logend; // log << log1 << "ThreadDb: there is more than one thread with file_id: " << file_id << logend;
else // else
if( rows == 0 ) // if( rows == 0 )
throw Error(WINIX_ERR_NO_THREAD); // throw Error(WINIX_ERR_NO_THREAD);
//
SetThreadColumns(r); // SetThreadColumns(r);
SetThread(r, 0, thread); // SetThread(r, 0, thread);
} // }
catch(const Error & e) // catch(const Error & e)
{ // {
status = e; // status = e;
} // }
//
ClearResult(r); // ClearResult(r);
//
return status; //return status;
} //}
Error TDb::GetThreads(const std::vector<long> & file_id_tab, std::vector<Thread> & thread_tab) //Error TDb::GetThreads(const std::vector<long> & file_id_tab, std::vector<Thread> & thread_tab)
{ //{
PGresult * r = 0; // PGresult * r = 0;
Error status = WINIX_ERR_OK; // Error status = WINIX_ERR_OK;
thread_tab.clear(); // thread_tab.clear();
//
if( file_id_tab.empty() ) // if( file_id_tab.empty() )
return status; // return status;
//
try // try
{ // {
CreateIdList(file_id_tab, list_id); // CreateIdList(file_id_tab, list_id);
//
// they should be sorted by file_id (they are used in a binary search later) // // they should be sorted by file_id (they are used in a binary search later)
query.Clear(); // query.Clear();
query << R("select thread.file_id, thread.replies, thread.closed, thread.last_item, " // query << R("select thread.file_id, thread.replies, thread.closed, thread.last_item, "
"item.date_modification, item.user_id, item.guest_name " // "item.date_modification, item.user_id, item.guest_name "
"from plugins.thread left join core.item on thread.last_item = item.id " // "from plugins.thread left join core.item on thread.last_item = item.id "
"where thread.file_id in ") << R(list_id) << R(" order by file_id asc;"); // "where thread.file_id in ") << R(list_id) << R(" order by file_id asc;");
//
r = AssertQuery(query); // r = AssertQuery(query);
AssertResult(r, PGRES_TUPLES_OK); // AssertResult(r, PGRES_TUPLES_OK);
//
int rows = Rows(r); // int rows = Rows(r);
SetThreadColumns(r); // SetThreadColumns(r);
//
for(int i=0 ; i<rows ; ++i) // for(int i=0 ; i<rows ; ++i)
{ // {
SetThread(r, i, thread_temp); // SetThread(r, i, thread_temp);
thread_tab.push_back(thread_temp); // thread_tab.push_back(thread_temp);
} // }
} // }
catch(const Error & e) // catch(const Error & e)
{ // {
status = e; // status = e;
} // }
//
ClearResult(r); // ClearResult(r);
//
return status; //return status;
} //}

View File

@ -5,7 +5,7 @@
*/ */
/* /*
* Copyright (c) 2010-2014, Tomasz Sowa * Copyright (c) 2010-2021, Tomasz Sowa
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -56,9 +56,9 @@ public:
high level interface high level interface
*/ */
Error AddThread(const Thread & thread); //Error AddThread(const Thread & thread);
Error GetThread(long file_id, Thread & thread); //Error GetThread(long file_id, Thread & thread);
Error GetThreads(const std::vector<long> & file_id_tab, std::vector<Thread> & thread_tab); //Error GetThreads(const std::vector<long> & file_id_tab, std::vector<Thread> & thread_tab);
Error RemoveThread(long file_id); Error RemoveThread(long file_id);
Error AddAnswer(long file_id, long answer_id); Error AddAnswer(long file_id, long answer_id);
@ -93,7 +93,8 @@ private:
DbTextStream query; DbTextStream query;
std::wstring list_id; std::wstring list_id;
int cfile_id, creplies, cclosed, clast_item, cdate_modification, cuser_id, cguest; int cfile_id, creplies, cclosed;
//int clast_item, cdate_modification, cuser_id, cguest;
Thread thread_temp; Thread thread_temp;
std::vector<long> file_id_tab; std::vector<long> file_id_tab;

View File

@ -452,8 +452,8 @@ void thread_sort_tab_last_item_date_modification_nice(Info & i)
{ {
Thread & thread = thread_info.thread_tab[thread_index]; Thread & thread = thread_info.thread_tab[thread_index];
if( thread.last_item_id != -1 ) if( thread.last_item.id != -1 )
print_date_nice(i, thread.last_item_date_modification); print_date_nice(i, thread.last_item.item_content.date_modification);
else else
print_date_nice(i, thread_info.item_sort_tab[item_sort_index]->item_content.date_modification); print_date_nice(i, thread_info.item_sort_tab[item_sort_index]->item_content.date_modification);
} }
@ -469,10 +469,10 @@ void thread_sort_tab_last_item_user(Info & i)
{ {
Thread & thread = thread_info.thread_tab[thread_index]; Thread & thread = thread_info.thread_tab[thread_index];
if( thread.last_item_id != -1 ) if( thread.last_item.id != -1 )
{ {
User * puser = system->users.GetUser(thread.last_item_user_id); User * puser = system->users.GetUser(thread.last_item.item_content.user_id);
print_user_name(i, puser, thread.last_item_guest_name); print_user_name(i, puser, thread.last_item.item_content.guest_name);
} }
else else
{ {

View File

@ -0,0 +1,122 @@
/*
* This file is a part of Winix
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2021, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
*
*/
#include "thread.h"
#include "finder.h"
namespace Winix
{
namespace Thread
{
Thread Thread::get_thread(morm::ModelConnector * model_connector, long file_id)
{
morm::Finder<Thread> finder(model_connector);
Thread thread = finder.
select().
where().
eq(L"file_id", file_id).
get();
return thread;
}
std::vector<Thread> Thread::get_threads(morm::ModelConnector * model_connector, const std::vector<long> & file_id_tab)
{
morm::Finder<Thread> finder(model_connector);
std::vector<Thread> threads;
if( !file_id_tab.empty() )
{
threads = finder.
select().
where().
in(L"file_id", file_id_tab).
raw("order by file_id asc").
get_vector();
}
return threads;
}
bool Thread::do_migration(int & current_table_version)
{
bool ok = true;
ok = ok && morm::Model::do_migration(current_table_version, 1, this, &Thread::do_migration_to_1);
return ok;
}
bool Thread::do_migration_to_1()
{
const char * str = R"sql(
CREATE TABLE plugins.thread (
file_id bigint NOT NULL,
replies integer,
last_item bigint,
closed smallint
);
)sql";
db_query(str);
return true;
}
//bool Thread::do_migration_to_2()
//{
// const char * str = R"sql(
//
// )sql";
//
// db_query(str);
// return true;
//}
} // namespace
} // namespace Winix

View File

@ -5,7 +5,7 @@
*/ */
/* /*
* Copyright (c) 2009-2014, Tomasz Sowa * Copyright (c) 2009-2021, Tomasz Sowa
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -37,47 +37,67 @@
#include <string> #include <string>
#include <string.h> #include <string.h>
#include "model.h"
#include "date/date.h" #include "date/date.h"
#include "models/item.h"
namespace Winix namespace Winix
{ {
namespace Thread namespace Thread
{ {
class Thread class Thread : public morm::Model
{ {
public: public:
long file_id; long file_id;
long replies; long replies;
bool closed; short int closed;
Winix::Item last_item;
// the last file in a thread
long last_item_id;
pt::Date last_item_date_modification;
long last_item_user_id;
std::wstring last_item_guest_name;
void Clear()
{
file_id = -1;
closed = false;
replies = 0;
last_item_id = -1;
last_item_user_id = -1;
last_item_date_modification.Clear();
last_item_guest_name.clear();
}
Thread() Thread()
{ {
Clear();
} }
void fields()
{
field(L"file_id", file_id, morm::FT::primary_key);
field(L"replies", replies);
field(L"closed", closed);
field(L"last_item", last_item, morm::FT::no_insertable | morm::FT::no_updatable | morm::FT::no_removable | morm::FT::foreign_key);
}
void table()
{
table_name(L"plugins", L"thread");
}
void after_insert()
{
}
bool do_migration(int & current_table_version);
static Thread get_thread(morm::ModelConnector * model_connector, long file_id);
static std::vector<Thread> get_threads(morm::ModelConnector * model_connector, const std::vector<long> & file_id_tab);
protected:
bool do_migration_to_1();
//bool do_migration_to_2();
}; };

View File

@ -0,0 +1,75 @@
/*
* This file is a part of Winix
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2021, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
*
*/
#include "threadfiles.h"
namespace Winix
{
namespace Thread
{
bool ThreadFiles::do_migration(int & current_table_version)
{
bool ok = true;
ok = ok && morm::Model::do_migration(current_table_version, 1, this, &ThreadFiles::do_migration_to_1);
return ok;
}
bool ThreadFiles::do_migration_to_1()
{
const char * str = R"sql(
CREATE TABLE plugins.thread_files (
file_id bigint,
answer_id bigint
);
)sql";
db_query(str);
return true;
}
} // namespace
} // namespace Winix

View File

@ -0,0 +1,97 @@
/*
* This file is a part of Winix
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2008-2021, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
*
*/
#ifndef headerfile_winix_plugins_thread_threadfiles
#define headerfile_winix_plugins_thread_threadfiles
#include <string>
#include <vector>
#include "model.h"
namespace Winix
{
namespace Thread
{
class ThreadFiles : public morm::Model
{
public:
long file_id;
long answer_id;
ThreadFiles()
{
}
void fields()
{
field(L"file_id", file_id);
field(L"answer_id", answer_id);
}
void table()
{
table_name(L"plugins", L"thread_files");
}
void after_insert()
{
}
bool do_migration(int & current_table_version);
protected:
bool do_migration_to_1();
};
} // namespace
} // namespace Winix
#endif