QList<ZealSearchResult> ZealDocsetsRegistry::getRelatedLinks(QString name, QString path) { QList<ZealSearchResult> results; // Get the url without the #anchor. QUrl mainUrl(path); mainUrl.setFragment(NULL); QString pageUrl(mainUrl.toString()); docsetEntry entry = docs[name]; // Prepare the query to look up all pages with the same url. QString query; if (entry.type == DASH) { query = QString("SELECT name, type, path FROM searchIndex WHERE path LIKE \"%1%%\"").arg(pageUrl); } else if (entry.type == ZDASH) { query = QString("SELECT ztoken.ztokenname, ztokentype.ztypename, zfilepath.zpath, ztokenmetainformation.zanchor " "FROM ztoken " "JOIN ztokenmetainformation ON ztoken.zmetainformation = ztokenmetainformation.z_pk " "JOIN zfilepath ON ztokenmetainformation.zfile = zfilepath.z_pk " "JOIN ztokentype ON ztoken.ztokentype = ztokentype.z_pk " "WHERE zfilepath.zpath = \"%1\"").arg(pageUrl); } else if (entry.type == ZEAL) { query = QString("SELECT name type, path FROM things WHERE path LIKE \"%1%%\"").arg(pageUrl); } QSqlQuery result = entry.db.exec(query); while (result.next()) { QString sectionName = result.value(0).toString(); QString sectionPath = result.value(2).toString(); QString parentName; if (entry.type == ZDASH) { sectionPath.append("#"); sectionPath.append(result.value(3).toString()); } normalizeName(sectionName, parentName, ""); results.append(ZealSearchResult(sectionName, "", sectionPath, name, QString())); } return results; }
void ZealDocsetsRegistry::_runQuery(const QString& rawQuery, int queryNum) { if(queryNum != lastQuery) return; // some other queries pending - ignore this one QList<ZealSearchResult> results; ZealSearchQuery query(rawQuery); QString preparedQuery = query.getSanitizedQuery(); bool hasDocsetFilter = query.hasDocsetFilter(); for (const ZealDocsetsRegistry::docsetEntry docset : docsets()) { if(hasDocsetFilter && !query.docsetPrefixMatch(docset.prefix)) { // Filter out this docset as the names don't match the docset prefix continue; } QString qstr; QSqlQuery q; QList<QList<QVariant> > found; bool withSubStrings = false; // %.%1% for long Django docset values like django.utils.http // %::%1% for long C++ docset values like std::set // %/%1% for long Go docset values like archive/tar QString subNames = QString(" or %1 like '%.%2%' escape '\\'"); subNames += QString(" or %1 like '%::%2%' escape '\\'"); subNames += QString(" or %1 like '%/%2%' escape '\\'"); while(found.size() < 100) { auto curQuery = preparedQuery; QString notQuery; // don't return the same result twice QString parentQuery; if(withSubStrings) { // if less than 100 found starting with query, search all substrings curQuery = "%"+preparedQuery; // don't return 'starting with' results twice if(docset.type == ZDASH) { notQuery = QString(" and not (ztokenname like '%1%' escape '\\' %2) ").arg(preparedQuery, subNames.arg("ztokenname", preparedQuery)); } else { if(docset.type == ZEAL) { notQuery = QString(" and not (t.name like '%1%' escape '\\') ").arg(preparedQuery); parentQuery = QString(" or t2.name like '%1%' escape '\\' ").arg(preparedQuery); } else { // DASH notQuery = QString(" and not (t.name like '%1%' escape '\\' %2) ").arg(preparedQuery, subNames.arg("t.name", preparedQuery)); } } } int cols = 3; if(docset.type == ZEAL) { qstr = QString("select t.name, t2.name, t.path from things t left join things t2 on t2.id=t.parent where " "(t.name like '%1%' escape '\\' %3) %2 order by length(t.name), lower(t.name) asc, t.path asc limit 100").arg(curQuery, notQuery, parentQuery); } else if(docset.type == DASH) { qstr = QString("select t.name, null, t.path from searchIndex t where (t.name " "like '%1%' escape '\\' %3) %2 order by length(t.name), lower(t.name) asc, t.path asc limit 100").arg(curQuery, notQuery, subNames.arg("t.name", curQuery)); } else if(docset.type == ZDASH) { cols = 4; qstr = QString("select ztokenname, null, zpath, zanchor from ztoken " "join ztokenmetainformation on ztoken.zmetainformation = ztokenmetainformation.z_pk " "join zfilepath on ztokenmetainformation.zfile = zfilepath.z_pk where (ztokenname " "like '%1%' escape '\\' %3) %2 order by length(ztokenname), lower(ztokenname) asc, zpath asc, " "zanchor asc limit 100").arg(curQuery, notQuery, subNames.arg("ztokenname", curQuery)); } q = db(docset.name).exec(qstr); while(q.next()) { QList<QVariant> values; for(int i = 0; i < cols; ++i) { values.append(q.value(i)); } found.append(values); } if(withSubStrings) break; withSubStrings = true; // try again searching for substrings } for(auto &row : found) { QString parentName; if(!row[1].isNull()) { parentName = row[1].toString(); } auto path = row[2].toString(); // FIXME: refactoring to use common code in ZealListModel and ZealDocsetsRegistry if(docset.type == ZDASH) { path += "#" + row[3].toString(); } auto itemName = row[0].toString(); normalizeName(itemName, parentName, row[1].toString()); results.append(ZealSearchResult(itemName, parentName, path, docset.name, preparedQuery)); } } qSort(results); if(queryNum != lastQuery) return; // some other queries pending - ignore this one queryResults = results; emit queryCompleted(); }
void ZealDocsetsRegistry::_runQuery(const QString& rawQuery, int queryNum) { if(queryNum != lastQuery) return; // some other queries pending - ignore this one QList<ZealSearchResult> results; ZealSearchQuery query(rawQuery); QString docsetPrefix = query.getDocsetFilter(); QString preparedQuery = query.getSanitizedQuery(); bool hasPrefixFilter = !docsetPrefix.isEmpty(); for (const QString &name : names()) { if (hasPrefixFilter && !name.contains(docsetPrefix, Qt::CaseInsensitive)) { // Filter out this docset as the names don't match the docset prefix continue; } QString qstr; QSqlQuery q; QList<QList<QVariant> > found; bool withSubStrings = false; // %.%1% for long Django docset values like django.utils.http // %::%1% for long C++ docset values like std::set // %/%1% for long Go docset values like archive/tar QString subNames = QString(" or %1 like '%.%2%' escape '\\'"); subNames += QString(" or %1 like '%::%2%' escape '\\'"); subNames += QString(" or %1 like '%/%2%' escape '\\'"); while(found.size() < 100) { auto curQuery = preparedQuery; QString notQuery; // don't return the same result twice QString parentQuery; if(withSubStrings) { // if less than 100 found starting with query, search all substrings curQuery = "%"+preparedQuery; // don't return 'starting with' results twice if(types[name] == ZDASH) { notQuery = QString(" and not (ztokenname like '%1%' escape '\\' %2) ").arg(preparedQuery, subNames.arg("ztokenname", preparedQuery)); } else { if(types[name] == ZEAL) { notQuery = QString(" and not (t.name like '%1%' escape '\\') ").arg(preparedQuery); parentQuery = QString(" or t2.name like '%1%' escape '\\' ").arg(preparedQuery); } else { // DASH notQuery = QString(" and not (t.name like '%1%' escape '\\' %2) ").arg(preparedQuery, subNames.arg("t.name", preparedQuery)); } } } int cols = 3; if(types[name] == ZEAL) { qstr = QString("select t.name, t2.name, t.path from things t left join things t2 on t2.id=t.parent where " "(t.name like '%1%' escape '\\' %3) %2 order by lower(t.name) asc, t.path asc limit 100").arg(curQuery, notQuery, parentQuery); } else if(types[name] == DASH) { qstr = QString("select t.name, null, t.path from searchIndex t where (t.name " "like '%1%' escape '\\' %3) %2 order by lower(t.name) asc, t.path asc limit 100").arg(curQuery, notQuery, subNames.arg("t.name", curQuery)); } else if(types[name] == ZDASH) { cols = 4; qstr = QString("select ztokenname, null, zpath, zanchor from ztoken " "join ztokenmetainformation on ztoken.zmetainformation = ztokenmetainformation.z_pk " "join zfilepath on ztokenmetainformation.zfile = zfilepath.z_pk where (ztokenname " "like '%1%' escape '\\' %3) %2 order by lower(ztokenname) asc, zpath asc, " "zanchor asc limit 100").arg(curQuery, notQuery, subNames.arg("ztokenname", curQuery)); } q = db(name).exec(qstr); while(q.next()) { QList<QVariant> values; for(int i = 0; i < cols; ++i) { values.append(q.value(i)); } found.append(values); } if(withSubStrings) break; withSubStrings = true; // try again searching for substrings } for(auto &row : found) { QString parentName; if(!row[1].isNull()) { parentName = row[1].toString(); } auto path = row[2].toString(); // FIXME: refactoring to use common code in ZealListModel and ZealDocsetsRegistry if(types[name] == DASH || types[name] == ZDASH) { path = QDir(QDir(QDir("Contents").filePath("Resources")).filePath("Documents")).filePath(path); } if(types[name] == ZDASH) { path += "#" + row[3].toString(); } auto itemName = row[0].toString(); QString separators[] = {".", "::", "/"}; for(unsigned i = 0; i < sizeof separators / sizeof *separators; ++i) { QString sep = separators[i]; if(itemName.indexOf(sep) != -1 && itemName.indexOf(sep) != 0 && row[1].isNull()) { auto splitted = itemName.split(sep); itemName = splitted.at(splitted.size()-1); parentName = splitted.at(splitted.size()-2); } } results.append(ZealSearchResult(itemName, parentName, path, name, preparedQuery)); } } qSort(results); if(queryNum != lastQuery) return; // some other queries pending - ignore this one queryResults = results; emit queryCompleted(); }