From: APTX Date: Sat, 31 Aug 2013 15:43:35 +0000 (+0200) Subject: Add Anime Search functions. X-Git-Url: https://gitweb.tyo.aptx.org/?a=commitdiff_plain;h=3cd0dd83c11fa27fe3ace223cf573eabc59064dd;p=localmylist.git Add Anime Search functions. --- diff --git a/localmylist/database.cpp b/localmylist/database.cpp index 7614c7f..c2cb4c2 100644 --- a/localmylist/database.cpp +++ b/localmylist/database.cpp @@ -134,6 +134,72 @@ bool Database::rollback() return true; } +AnimeTitle Database::animeSearchBestMatch(const QString &query) +{ + QList ret = animeSearch(query, 1); + if (ret.count()) + return ret[0]; + return AnimeTitle(); +} + +QList Database::animeSearch(const QString &query, int limit) +{ + QList ret; + + QSqlQuery &q = prepare( + "SELECT at.title_id, at.aid, at.type, at.language, at.title " + " FROM anime_title at " + " WHERE at.title ILIKE :query " + " ORDER BY at.title <-> :query2 ASC " + " LIMIT :limit"); + q.bindValue(":query", query); + q.bindValue(":query2", query); + q.bindValue(":limit", limit); + + if (!exec(q)) + return ret; + + QSqlResultIterator it(q); + while (q.next()) + { + AnimeTitle data; + readAnimeTitleData(it, data); + ret << data; + } + + q.finish(); + + return ret; +} + +QList Database::animeSearchSimmilar(const QString &query, int limit) +{ + QList ret; + + QSqlQuery &q = prepare( + "SELECT at.title_id, at.aid, at.type, at.language, at.title " + " FROM anime_title at " + " ORDER BY at.title <-> :query ASC " + " LIMIT :limit"); + q.bindValue(":query", query); + q.bindValue(":limit", limit); + + if (!exec(q)) + return ret; + + QSqlResultIterator it(q); + while (q.next()) + { + AnimeTitle data; + readAnimeTitleData(it, data); + ret << data; + } + + q.finish(); + + return ret; +} + OpenFileData Database::firstUnwatchedByExactTitle(const QString &title) { QSqlQuery &q = prepare( @@ -1657,7 +1723,7 @@ void Database::readAnimeTitleData(const SqlResultIteratorInterface &result, Anim data.titleId = result.value(offset++).toInt(); data.aid = result.value(offset++).toInt(); data.type = AnimeTitle::TitleType(result.value(offset++).toInt()); - data.language = result.value(offset++).toString(); + data.language = result.value(offset++).toString().trimmed(); data.title = result.value(offset++).toString(); } @@ -2198,4 +2264,13 @@ void RaiiTransaction::commit() c = true; } +QString toSearchQuery(const QString &string) +{ + const static QChar anyChar = QChar('%'); + QString ret = string.trimmed(); + ret.replace(QRegExp("\\s+"), anyChar); + ret = ret.append(anyChar).prepend(anyChar); + return ret; +} + } // namespace LocalMyList diff --git a/localmylist/database.h b/localmylist/database.h index 996450b..89a8bf8 100644 --- a/localmylist/database.h +++ b/localmylist/database.h @@ -47,6 +47,10 @@ public slots: bool commit(); bool rollback(); + LocalMyList::AnimeTitle animeSearchBestMatch(const QString &query); + QList animeSearch(const QString &query, int limit = 100); + QList animeSearchSimmilar(const QString &query, int limit = 5); + LocalMyList::OpenFileData firstUnwatchedByExactTitle(const QString &title); LocalMyList::OpenFileData firstUnwatchedByTitle(const QString &title); LocalMyList::OpenFileData firstUnwatchedByAid(int aid); @@ -221,6 +225,8 @@ public: void commit(); }; +QString toSearchQuery(const QString &string); + } // namespace LocalMyList Q_DECLARE_METATYPE(LocalMyList::Database*) diff --git a/localmylist/databaseclasses.h b/localmylist/databaseclasses.h index 0366bda..75d6c09 100644 --- a/localmylist/databaseclasses.h +++ b/localmylist/databaseclasses.h @@ -262,6 +262,10 @@ struct LOCALMYLISTSHARED_EXPORT DatabaseConnectionSettings } // namespace LocalMyList +Q_DECLARE_METATYPE(LocalMyList::AnimeTitle) +Q_DECLARE_METATYPE(LocalMyList::AnimeTitle*) +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(QList) Q_DECLARE_METATYPE(LocalMyList::Anime) Q_DECLARE_METATYPE(LocalMyList::Anime*) Q_DECLARE_METATYPE(QList) diff --git a/localmylist/scriptable.cpp b/localmylist/scriptable.cpp index fff61a7..c33823c 100644 --- a/localmylist/scriptable.cpp +++ b/localmylist/scriptable.cpp @@ -12,6 +12,13 @@ void registerTypes(QScriptEngine *engine) qScriptRegisterMetaType(engine, Scriptable::toScriptValue, Scriptable::fromScriptValue); qScriptRegisterMetaType(engine, Scriptable::toScriptValue, Scriptable::fromScriptValue); + engine->globalObject().setProperty("toSearchQuery", engine->newFunction(Scriptable::toSearchQuery)); + + Scriptable::AnimeTitle *AnimeTitlePrototype = new Scriptable::AnimeTitle(); + engine->setDefaultPrototype(qMetaTypeId(), engine->newQObject(AnimeTitlePrototype)); + engine->setDefaultPrototype(qMetaTypeId(), engine->newQObject(AnimeTitlePrototype)); + qScriptRegisterSequenceMetaType >(engine); + qScriptRegisterSequenceMetaType >(engine); Scriptable::Anime *AnimePrototype = new Scriptable::Anime(); engine->setDefaultPrototype(qMetaTypeId(), engine->newQObject(AnimePrototype)); engine->setDefaultPrototype(qMetaTypeId(), engine->newQObject(AnimePrototype)); @@ -82,6 +89,40 @@ void registerTypes(QScriptEngine *engine) namespace Scriptable { +::LocalMyList::AnimeTitle *AnimeTitle::thisObj() const +{ + return qscriptvalue_cast< ::LocalMyList::AnimeTitle*>(thisObject()); +} + +AnimeTitle::AnimeTitle(QObject *parent) : QObject(parent), QScriptable() +{ +} + +QString titleTypeToString(int titleType) +{ + switch (::LocalMyList::AnimeTitle::TitleType(titleType)) + { + case ::LocalMyList::AnimeTitle::PrimaryTitle: + return "Primary"; + case ::LocalMyList::AnimeTitle::OfficialTitle: + return "Official"; + case ::LocalMyList::AnimeTitle::ShortTitle: + return "Short"; + case ::LocalMyList::AnimeTitle::Synonym: + return "Synonym"; + } + return "Unknown"; +} + +QString AnimeTitle::toString() const +{ + return QString("AnimeTitle('%1', %2, %3, %4)") + .arg(read_title()).arg(read_language()) + .arg(titleTypeToString(read_type())).arg(read_aid()); +} + +// -------------------------------------------------------------------------------- + ::LocalMyList::Anime *Anime::thisObj() const { return qscriptvalue_cast< ::LocalMyList::Anime*>(thisObject()); @@ -260,6 +301,64 @@ QString DatabaseConnectionSettings::toString() const // Generated // -------------------------------------------------------------------------------- +int AnimeTitle::read_aid() const +{ + auto o = thisObj(); + if (!o) return int(); + return o->aid; +} + +void AnimeTitle::write_aid(int val) +{ + auto o = thisObj(); + if (!o) return; + o->aid = val; +} + +int AnimeTitle::read_type() const +{ + auto o = thisObj(); + if (!o) return int(); + return int(o->type); +} + +void AnimeTitle::write_type(int val) +{ + auto o = thisObj(); + if (!o) return; + o->type = ::LocalMyList::AnimeTitle::TitleType(val); +} + +QString AnimeTitle::read_language() const +{ + auto o = thisObj(); + if (!o) return QString(); + return o->language; +} + +void AnimeTitle::write_language(QString val) +{ + auto o = thisObj(); + if (!o) return; + o->language = val; +} + +QString AnimeTitle::read_title() const +{ + auto o = thisObj(); + if (!o) return QString(); + return o->title; +} + +void AnimeTitle::write_title(QString val) +{ + auto o = thisObj(); + if (!o) return; + o->title = val; +} + +// -------------------------------------------------------------------------------- + int Anime::read_aid() const { auto o = thisObj(); @@ -2087,5 +2186,12 @@ QScriptValue DatabaseConnectionSettings_ctor(QScriptContext *, QScriptEngine *en return engine->toScriptValue(::LocalMyList::DatabaseConnectionSettings()); } +QScriptValue toSearchQuery(QScriptContext *ctx, QScriptEngine *engine) +{ + if (!ctx->argumentCount()) + return engine->toScriptValue(QString()); + return engine->toScriptValue(::LocalMyList::toSearchQuery(ctx->argument(0).toString())); +} + } // namespace Scriptable } // namespace LocalMyList diff --git a/localmylist/scriptable.h b/localmylist/scriptable.h index a3e4976..ee85499 100644 --- a/localmylist/scriptable.h +++ b/localmylist/scriptable.h @@ -10,6 +10,7 @@ namespace LocalMyList { +struct AnimeTitle; struct Anime; struct Episode; struct File; @@ -36,24 +37,35 @@ template void fromScriptValue(const QScriptValue &value, T &t) t = qobject_cast(value.toQObject()); } -/* -struct LOCALMYLISTSHARED_EXPORT AnimeTitle +struct LOCALMYLISTSHARED_EXPORT AnimeTitle : public QObject, protected QScriptable { - enum TitleType { - PrimaryTitle = 1, - Synonym = 2, - ShortTitle = 3, - OfficialTitle = 4 - }; - - int aid; - TitleType type; - QString language; - QString title; - - AnimeTitle(int aid = 0, TitleType type = PrimaryTitle, const QString &language = QString(), const QString &title = QString()); + Q_OBJECT + Q_PROPERTY(int aid READ read_aid WRITE write_aid) + Q_PROPERTY(int type READ read_type WRITE write_type) + Q_PROPERTY(QString language READ read_language WRITE write_language) + Q_PROPERTY(QString title READ read_title WRITE write_title) + + ::LocalMyList::AnimeTitle *thisObj() const; + +public: + AnimeTitle(QObject *parent = 0); + +public slots: + QString toString() const; + +public: + int read_aid() const; + void write_aid(int val); + + int read_type() const; + void write_type(int val); + + QString read_language() const; + void write_language(QString val); + + QString read_title() const; + void write_title(QString val); }; -*/ class LOCALMYLISTSHARED_EXPORT Anime : public QObject, protected QScriptable { @@ -710,6 +722,7 @@ QScriptValue HostInfo_ctor(QScriptContext *, QScriptEngine *engine); QScriptValue OpenFileData_ctor(QScriptContext *, QScriptEngine *engine); QScriptValue DatabaseConnectionSettings_ctor(QScriptContext *, QScriptEngine *engine); +QScriptValue toSearchQuery(QScriptContext *, QScriptEngine *engine); } // namespace Scriptable } // namespace LocalMyList diff --git a/localmylist/share/schema/schema.sql b/localmylist/share/schema/schema.sql index 258f66a..9a3ddb1 100644 --- a/localmylist/share/schema/schema.sql +++ b/localmylist/share/schema/schema.sql @@ -45,7 +45,7 @@ CREATE TABLE anime_title ( CONSTRAINT unique_title UNIQUE (aid, type, language, title) ); CREATE INDEX aid_idx ON anime_title USING btree (aid); -CREATE INDEX title_idx ON anime_title USING gin (to_tsvector('simple'::regconfig, (title)::text)); +CREATE INDEX title_gist_trgm_idx ON anime_title USING gist (title gist_trgm_ops); CREATE INDEX language_idx ON anime_title USING hash (language); CREATE TABLE episode (