DistroqueryAPI: getRepositoryPackages: added pagination from query string support

This commit is contained in:
Silvan Calarco 2024-07-06 17:10:15 +02:00
parent aa283cd60c
commit f1fd8ef275
2 changed files with 71 additions and 10 deletions

View File

@ -104,11 +104,26 @@ json DistroqueryAPI::getPackageSourceDetailsById(configTag* ct, long id) {
return j;
}
json DistroqueryAPI::getRepositoryPackages(string repository) {
json DistroqueryAPI::getRepositoryPackages(string repository, int per_page, int page) {
json j;
string sql;
sqlite3_stmt *stmt;
j["query"] = {};
j["query"]["repository"] = repository;
j["query"]["per_page"] = per_page;
j["query"]["page"] = page;
if (per_page < 1) {
j["error"] = "'per_page' query var must be >= 1";
return j;
}
if (page < 1) {
j["error"] = "'page' query var must be >= 1";
return j;
}
struct configTag* ct = findRepositoryByTag(repository.c_str());
if (ct == NULL) {
j["error"] = "repository with tag '" + repository + "' does not exist";
@ -121,16 +136,29 @@ json DistroqueryAPI::getRepositoryPackages(string repository) {
return j;
}
sql = "SELECT * FROM sources ORDER BY name COLLATE NOCASE ASC";
sql = "SELECT COUNT(*) OVER() AS total_count,* FROM sources ORDER BY name COLLATE NOCASE ASC"
" LIMIT " + to_string(per_page) +
" OFFSET " + to_string(per_page * (page -1));
if (sqlite3_prepare_v2(db, sql.c_str(), sql.length(), &stmt, NULL) == SQLITE_OK) {
j = json::array();
json packages = json::array();
long count = 0;
while (sqlite3_step(stmt) == SQLITE_ROW) {
count++;
// Set total packages count
if (j["query"].find("total") == j["query"].end()) {
long total_count = sqlite3_column_int(stmt,sqlite3_find_column_id(stmt, NULL, "total_count"));
j["query"]["total"] = total_count;
j["query"]["pages"] = total_count / per_page + 1;
j["query"]["from"] = per_page * (page - 1) + 1;
}
json package;
package["name"] = reinterpret_cast<const char*>(sqlite3_column_text(stmt,sqlite3_find_column_id(stmt, NULL, "name")));
package["summary"] = reinterpret_cast<const char*>(sqlite3_column_text(stmt,sqlite3_find_column_id(stmt, NULL, "summary")));
j.push_back(package);
packages.push_back(package);
}
sqlite3_finalize(stmt);
j["query"]["to"] = per_page * (page - 1) + count;
j["packages"] = packages;
} else {
j["error"] = "error preparing query '" + sql + "'";
return j;
@ -300,7 +328,7 @@ json DistroqueryAPI::getPackageDetails(string repository, string package, string
}
// Provides
sql = "SELECT * FROM provides,provided WHERE provides.id_package=" + to_string(id) +
sql = "SELECT * FROM provides,provided WHERE provides.id_package=" + to_string(id) +
" AND provided.id=provides.id_provided ORDER BY provided.name";
j["provides"] = json::array();
if (sqlite3_prepare_v2(db, sql.c_str(), sql.length(), &stmt2, NULL) == SQLITE_OK) {
@ -375,15 +403,31 @@ void DistroqueryAPI::getApiResponse(string path_info) {
cout << "Content-Type: application/json;charset=utf-8\n\n" << endl;
string path, query_string;
std::vector<std::string> path_split;
vector<string> path_split;
map<string,string> query_vars;
std::vector<std::string> v = split(path_info, "?");
vector<string> v = split(path_info, "?");
if (v.size() > 0) {
path = v[0];
path_split = split(path, "/");
}
if (v.size() > 1) query_string = v[1];
if (v.size() > 1) {
query_string = v[1];
vector<string> query_split = split(query_string, "&");
for (auto q:query_split) {
vector<string> arg_split = split(q, "=");
if (arg_split.size() == 1) {
query_vars[arg_split[0]] = "";
} else if (arg_split.size() == 2) {
query_vars[arg_split[0]] = arg_split[1];
} else {
cerr << "Error parsing query_string entry '" << q << "'" << endl;
}
}
}
if (path_split.size() > 0 ) {
if (path_split[0] == "repositories") {
@ -395,7 +439,24 @@ void DistroqueryAPI::getApiResponse(string path_info) {
// API service: repository
if (path_split.size() != 2)
sendErrorResponse("expected exactly 2 arguments for " + path_split[0]);
auto packages = getRepositoryPackages(path_split[1]);
// Pagination
unsigned int per_page = 100;
unsigned int page = 1;
if (query_vars.find("per_page") != query_vars.end()) {
try {
per_page = atoi(query_vars["per_page"].c_str());
} catch (exception const & e) {
cerr << "Error converting '" << query_vars["per_page"] << " to int: " << e.what() << endl;
}
}
if (query_vars.find("page") != query_vars.end()) {
try {
page = atoi(query_vars["page"].c_str());
} catch (exception const & e) {
cerr << "Error converting '" << query_vars["page"] << " to int: " << e.what() << endl;
}
}
auto packages = getRepositoryPackages(path_split[1], per_page, page);
cout << packages.dump();
} else if (path_split[0] == "package") {
// API service: package

View File

@ -41,7 +41,7 @@ class DistroqueryAPI {
configTag *config;
json configToJsonRepositories();
void sendErrorResponse(string message);
json getRepositoryPackages(string repository);
json getRepositoryPackages(string repository, int per_page, int page);
json getPackageSourceDetailsById(configTag* ct, long id);
json getPackageSourceDetails(string repository, string package);
json getBuiltPackagesFromSourceID(configTag* ct, long id);