~ubuntu-branches/ubuntu/saucy/goldencheetah/saucy

« back to all changes in this revision

Viewing changes to src/TrainDB.cpp

  • Committer: Package Import Robot
  • Author(s): KURASHIKI Satoru
  • Date: 2013-08-18 07:02:45 UTC
  • mfrom: (4.1.8 sid)
  • Revision ID: package-import@ubuntu.com-20130818070245-zgdvb47e1k3mtgil
Tags: 3.0-3
debian/control: remove needless dependency. (Closes: #719571)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2012 Mark Liversedge (liversedge@gmail.com)
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify it
 
5
 * under the terms of the GNU General Public License as published by the Free
 
6
 * Software Foundation; either version 2 of the License, or (at your option)
 
7
 * any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful, but WITHOUT
 
10
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
11
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 
12
 * more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License along
 
15
 * with this program; if not, write to the Free Software Foundation, Inc., 51
 
16
 * Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 
17
 */
 
18
 
 
19
#include "TrainDB.h"
 
20
#include "ErgFile.h"
 
21
 
 
22
// DB Schema Version - YOU MUST UPDATE THIS IF THE TRAIN DB SCHEMA CHANGES
 
23
 
 
24
// Revision History
 
25
// Rev Date         Who                What Changed
 
26
// 01  21 Dec 2012  Mark Liversedge    Initial Build
 
27
 
 
28
static int TrainDBSchemaVersion = 1;
 
29
TrainDB *trainDB;
 
30
 
 
31
TrainDB::TrainDB(QDir home) : home(home)
 
32
{
 
33
    // we live above the rider directory
 
34
        initDatabase(home);
 
35
}
 
36
 
 
37
void TrainDB::closeConnection()
 
38
{
 
39
    dbconn.close();
 
40
}
 
41
 
 
42
TrainDB::~TrainDB()
 
43
{
 
44
    closeConnection();
 
45
}
 
46
 
 
47
void
 
48
TrainDB::initDatabase(QDir home)
 
49
{
 
50
 
 
51
 
 
52
    if(dbconn.isOpen()) return;
 
53
 
 
54
    // get a connection
 
55
    db = QSqlDatabase::addDatabase("QSQLITE", "1");
 
56
    db.setDatabaseName(home.absolutePath() + "/trainDB"); 
 
57
    dbconn = db.database("1");
 
58
 
 
59
    if (!dbconn.isOpen()) {
 
60
        QMessageBox::critical(0, qApp->translate("TrainDB","Cannot open database"),
 
61
                       qApp->translate("TrainDB","Unable to establish a database connection.\n"
 
62
                                       "This feature requires SQLite support. Please read "
 
63
                                       "the Qt SQL driver documentation for information how "
 
64
                                       "to build it.\n\n"
 
65
                                       "Click Cancel to exit."), QMessageBox::Cancel);
 
66
    } else {
 
67
 
 
68
        // create database - does nothing if its already there
 
69
        createDatabase();
 
70
    }
 
71
}
 
72
 
 
73
// rebuild effectively drops and recreates all tables
 
74
// but not the version table, since its about deleting
 
75
// user data (e.g. when rescanning their hard disk)
 
76
void
 
77
TrainDB::rebuildDB()
 
78
{
 
79
    dropWorkoutTable();
 
80
    createWorkoutTable();
 
81
    dropVideoTable();
 
82
    createVideoTable();
 
83
}
 
84
 
 
85
bool TrainDB::createVideoTable()
 
86
{
 
87
    QSqlQuery query(dbconn);
 
88
    bool rc;
 
89
    bool createTables = true;
 
90
 
 
91
    // does the table exist?
 
92
    rc = query.exec("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;");
 
93
    if (rc) {
 
94
        while (query.next()) {
 
95
 
 
96
            QString table = query.value(0).toString();
 
97
            if (table == "videos") {
 
98
                createTables = false;
 
99
                break;
 
100
            }
 
101
        }
 
102
    }
 
103
    // we need to create it!
 
104
    if (rc && createTables) {
 
105
 
 
106
        QString createVideoTable = "create table videos (filepath varchar primary key,"
 
107
                                    "filename varchar,"
 
108
                                    "timestamp integer,"
 
109
                                    "length integer);";
 
110
 
 
111
        rc = query.exec(createVideoTable);
 
112
 
 
113
        // insert the 'DVD' record for playing currently loaded DVD
 
114
        // need to resolve DVD playback in v3.1, there is an open feature request for this.
 
115
        // rc = query.exec("INSERT INTO videos (filepath, filename) values (\"\", \"DVD\");");
 
116
 
 
117
        // add row to version database
 
118
        query.exec("DELETE FROM version where table_name = \"videos\"");
 
119
 
 
120
        // insert into table
 
121
        query.prepare("INSERT INTO version (table_name, schema_version, creation_date) values (?,?,?);");
 
122
        query.addBindValue("videos");
 
123
            query.addBindValue(TrainDBSchemaVersion);
 
124
            query.addBindValue(QDateTime::currentDateTime().toTime_t());
 
125
        rc = query.exec();
 
126
    }
 
127
    return rc;
 
128
}
 
129
 
 
130
bool TrainDB::createWorkoutTable()
 
131
{
 
132
    QSqlQuery query(dbconn);
 
133
    bool rc;
 
134
    bool createTables = true;
 
135
 
 
136
    // does the table exist?
 
137
    rc = query.exec("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;");
 
138
    if (rc) {
 
139
        while (query.next()) {
 
140
 
 
141
            QString table = query.value(0).toString();
 
142
            if (table == "workouts") {
 
143
                createTables = false;
 
144
                break;
 
145
            }
 
146
        }
 
147
    }
 
148
    // we need to create it!
 
149
    if (rc && createTables) {
 
150
 
 
151
        QString createMetricTable = "create table workouts (filepath varchar primary key,"
 
152
                                    "filename,"
 
153
                                    "timestamp integer,"
 
154
                                    "description varchar,"
 
155
                                    "source varchar,"
 
156
                                    "ftp integer,"
 
157
                                    "length integer,"
 
158
                                    "coggan_tss integer,"
 
159
                                    "coggan_if integer,"
 
160
                                    "elevation integer,"
 
161
                                    "grade double );";
 
162
 
 
163
        rc = query.exec(createMetricTable);
 
164
 
 
165
        // adding a space at the front of string to make manual mode always
 
166
        // appear first in a sorted list is a bit of a hack, but works ok
 
167
        QString manualErg = QString("INSERT INTO workouts (filepath, filename) values (\"//1\", \"%1\");")
 
168
                         .arg(tr(" Manual Erg Mode"));
 
169
        rc = query.exec(manualErg);
 
170
 
 
171
        QString manualCrs = QString("INSERT INTO workouts (filepath, filename) values (\"//2\", \"%1\");")
 
172
                         .arg(tr(" Manual Slope Mode"));
 
173
        rc = query.exec(manualCrs);
 
174
 
 
175
        // add row to version database
 
176
        query.exec("DELETE FROM version where table_name = \"workouts\"");
 
177
 
 
178
        // insert into table
 
179
        query.prepare("INSERT INTO version (table_name, schema_version, creation_date) values (?,?,?);");
 
180
        query.addBindValue("workouts");
 
181
            query.addBindValue(TrainDBSchemaVersion);
 
182
            query.addBindValue(QDateTime::currentDateTime().toTime_t());
 
183
        rc = query.exec();
 
184
    }
 
185
    return rc;
 
186
}
 
187
 
 
188
bool TrainDB::dropVideoTable()
 
189
{
 
190
    QSqlQuery query("DROP TABLE videos", dbconn);
 
191
    bool rc = query.exec();
 
192
    return rc;
 
193
}
 
194
 
 
195
bool TrainDB::dropWorkoutTable()
 
196
{
 
197
    QSqlQuery query("DROP TABLE workouts", dbconn);
 
198
    bool rc = query.exec();
 
199
    return rc;
 
200
}
 
201
 
 
202
bool TrainDB::createDatabase()
 
203
{
 
204
    // check schema version and if missing recreate database
 
205
    checkDBVersion();
 
206
 
 
207
    // Workouts
 
208
        createWorkoutTable();
 
209
        createVideoTable();
 
210
 
 
211
    return true;
 
212
}
 
213
 
 
214
void TrainDB::checkDBVersion()
 
215
{
 
216
    // can we get a version number?
 
217
    QSqlQuery query("SELECT table_name, schema_version, creation_date from version;", dbconn);
 
218
 
 
219
    bool rc = query.exec();
 
220
 
 
221
    if (!rc) {
 
222
        // we couldn't read the version table properly
 
223
        // it must be out of date!!
 
224
 
 
225
        QSqlQuery dropM("DROP TABLE version", dbconn);
 
226
        dropM.exec();
 
227
 
 
228
        // recreate version table and add one entry
 
229
        QSqlQuery version("CREATE TABLE version ( table_name varchar primary key, schema_version integer, creation_date date );", dbconn);
 
230
        version.exec();
 
231
 
 
232
        // wipe away whatever (if anything is there)
 
233
        dropWorkoutTable();
 
234
        createWorkoutTable();
 
235
 
 
236
        dropVideoTable();
 
237
        createVideoTable();
 
238
        return;
 
239
    }
 
240
 
 
241
    // ok we checked out ok, so lets adjust db schema to reflect
 
242
    // tne current version / crc
 
243
    bool dropWorkout = false;
 
244
    bool dropVideo = false;
 
245
    while (query.next()) {
 
246
 
 
247
        QString table_name = query.value(0).toString();
 
248
        int currentversion = query.value(1).toInt();
 
249
 
 
250
        if (table_name == "workouts" && currentversion != TrainDBSchemaVersion) dropWorkout = true;
 
251
        if (table_name == "videos" && currentversion != TrainDBSchemaVersion) dropVideo = true;
 
252
    }
 
253
    query.finish();
 
254
 
 
255
    // "workouts" table, is it up-to-date?
 
256
    if (dropWorkout) dropWorkoutTable();
 
257
    if (dropVideo) dropVideoTable();
 
258
}
 
259
 
 
260
int TrainDB::getCount()
 
261
{
 
262
    // how many workouts are there?
 
263
    QSqlQuery query("SELECT count(*) from workouts;", dbconn);
 
264
    bool rc = query.exec();
 
265
 
 
266
    if (rc) {
 
267
        while (query.next()) {
 
268
            return query.value(0).toInt();
 
269
        }
 
270
    }
 
271
 
 
272
    return 0;
 
273
}
 
274
 
 
275
int TrainDB::getDBVersion()
 
276
{
 
277
    int schema_version = -1;
 
278
 
 
279
    // can we get a version number?
 
280
    QSqlQuery query("SELECT schema_version from version;", dbconn);
 
281
 
 
282
    bool rc = query.exec();
 
283
 
 
284
    if (rc) {
 
285
        while (query.next()) {
 
286
            if (query.value(0).toInt() > schema_version)
 
287
                schema_version = query.value(0).toInt();
 
288
        }
 
289
    }
 
290
    query.finish();
 
291
    return schema_version;
 
292
}
 
293
 
 
294
/*----------------------------------------------------------------------
 
295
 * CRUD routines
 
296
 *----------------------------------------------------------------------*/
 
297
 
 
298
bool TrainDB::deleteWorkout(QString pathname)
 
299
{
 
300
        QSqlQuery query(dbconn);
 
301
    QDateTime timestamp = QDateTime::currentDateTime();
 
302
 
 
303
    // zap the current row - if there is one
 
304
    query.prepare("DELETE FROM workouts WHERE filepath = ?;");
 
305
    query.addBindValue(pathname);
 
306
 
 
307
    return query.exec();
 
308
}
 
309
 
 
310
bool TrainDB::importWorkout(QString pathname, ErgFile *ergFile)
 
311
{
 
312
        QSqlQuery query(dbconn);
 
313
    QDateTime timestamp = QDateTime::currentDateTime();
 
314
 
 
315
    // zap the current row - if there is one
 
316
    query.prepare("DELETE FROM workouts WHERE filepath = ?;");
 
317
    query.addBindValue(pathname);
 
318
    query.exec();
 
319
 
 
320
    // construct an insert statement
 
321
    QString insertStatement = "insert into workouts ( filepath, "
 
322
                                    "filename,"
 
323
                                    "timestamp,"
 
324
                                    "description,"
 
325
                                    "source,"
 
326
                                    "ftp,"
 
327
                                    "length,"
 
328
                                    "coggan_tss,"
 
329
                                    "coggan_if,"
 
330
                                    "elevation,"
 
331
                                    "grade ) values ( ?,?,?,?,?,?,?,?,?,?,? );";
 
332
        query.prepare(insertStatement);
 
333
 
 
334
    // filename, timestamp, ride date
 
335
        query.addBindValue(pathname);
 
336
        query.addBindValue(QFileInfo(pathname).fileName());
 
337
        query.addBindValue(timestamp);
 
338
    query.addBindValue(ergFile->Name);
 
339
        query.addBindValue(ergFile->Source);
 
340
        query.addBindValue(ergFile->Ftp);
 
341
        query.addBindValue((int)ergFile->Duration);
 
342
        query.addBindValue(ergFile->TSS);
 
343
        query.addBindValue(ergFile->IF);
 
344
        query.addBindValue(ergFile->ELE);
 
345
        query.addBindValue(ergFile->GRADE);
 
346
 
 
347
    // go do it!
 
348
        bool rc = query.exec();
 
349
 
 
350
        return rc;
 
351
}
 
352
 
 
353
bool TrainDB::deleteVideo(QString pathname)
 
354
{
 
355
        QSqlQuery query(dbconn);
 
356
    QDateTime timestamp = QDateTime::currentDateTime();
 
357
 
 
358
    // zap the current row - if there is one
 
359
    query.prepare("DELETE FROM videos WHERE filepath = ?;");
 
360
    query.addBindValue(pathname);
 
361
    return query.exec();
 
362
}
 
363
 
 
364
bool TrainDB::importVideo(QString pathname)
 
365
{
 
366
        QSqlQuery query(dbconn);
 
367
    QDateTime timestamp = QDateTime::currentDateTime();
 
368
 
 
369
    // zap the current row - if there is one
 
370
    query.prepare("DELETE FROM videos WHERE filepath = ?;");
 
371
    query.addBindValue(pathname);
 
372
    query.exec();
 
373
 
 
374
    // construct an insert statement
 
375
    QString insertStatement = "insert into videos ( filepath,filename ) values ( ?,? );";
 
376
        query.prepare(insertStatement);
 
377
 
 
378
    // filename, timestamp, ride date
 
379
        query.addBindValue(pathname);
 
380
        query.addBindValue(QFileInfo(pathname).fileName());
 
381
 
 
382
    // go do it!
 
383
        bool rc = query.exec();
 
384
 
 
385
        return rc;
 
386
}