Skip to content

Commit

Permalink
REST: Added POST /db/_query handler
Browse files Browse the repository at this point in the history
  • Loading branch information
snej committed Aug 29, 2024
1 parent 1585ab9 commit 5be8e84
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 0 deletions.
69 changes: 69 additions & 0 deletions REST/RESTListener+Handlers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "c4Collection.hh"
#include "c4Document.hh"
#include "c4Database.hh"
#include "c4Query.hh"
#include "c4DocEnumerator.hh"
#include "fleece/Expert.hh"
#include <functional>
Expand Down Expand Up @@ -367,4 +368,72 @@ namespace litecore::REST {
t.commit();
}

#pragma mark - FUNCTION/QUERY HANDLERS:

void RESTListener::handleFunction(RequestResponse& rq, C4Collection* coll) {
rq.respondWithStatus(HTTPStatus::NotImplemented);
}

void RESTListener::handleQuery(RequestResponse& rq, C4Collection* coll) {
Dict body = rq.bodyAsJSON().asDict();

// Compile the query:
auto queryStr = body["query"].asString();
if (!queryStr)
return rq.respondWithStatus(HTTPStatus::BadRequest, "Request body must be a JSON object with a 'query' string");
Retained<C4Query> query;
int errPos;
try {
query = coll->newQuery(kC4N1QLQuery, queryStr, &errPos);
} catch (exception const& x) {
return rq.respondWithStatus(HTTPStatus::BadRequest, ("Invalid SQL++ query: "s + x.what()).c_str());
}

// Verify parameter values match query's parameters:
auto paramNames = query->parameterNames();
Dict params = body["params"].asDict();
for (Dict::iterator i(params); i; ++i) {
if (string name(i.keyString()); paramNames.contains(string(name))) {
paramNames.erase(name);
} else {
return rq.respondWithStatus(HTTPStatus::BadRequest,
("Query has no parameter named " + name).c_str());
}
}
if (!paramNames.empty()) {
if (params)
return rq.respondWithStatus(HTTPStatus::BadRequest,
("Missing value for parameter " + *paramNames.begin()).c_str());
else
return rq.respondWithStatus(HTTPStatus::BadRequest, "Request body must contain a 'params' object");
}

// Set the parameter values:
if (params) {
Encoder enc;
enc.writeValue(params);
query->setParameters(enc.finish());
}

// Run!
rq.setHeader("Content-Type", "application/json");
rq.setChunked();
rq.write("[\n");
JSONEncoder json;
unsigned nCols = query->columnCount();
auto e = query->run();
while (e.next()) {
json.beginDict(nCols);
for (unsigned col = 0; col < nCols; ++col) {
json.writeKey(query->columnTitle(col));
json.writeValue(e.column(col));
}
json.endDict();
rq.write(json.finish());
rq.write("\n");
rq.flush(32768);
}
rq.write("]\n");
}

} // namespace litecore::REST
2 changes: 2 additions & 0 deletions REST/RESTListener.cc
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ namespace litecore::REST {
addCollectionHandler(Method::GET, "/[^_][^/]*/_all_docs", &RESTListener::handleGetAllDocs);
addCollectionHandler(Method::POST, "/[^_][^/]*/_bulk_docs", &RESTListener::handleBulkDocs);
addCollectionHandler(Method::GET, "/[^_][^/]*/_changes", &RESTListener::handleChanges);
addCollectionHandler(Method::GET, "/[^_][^/]*/_function/[^/]+", &RESTListener::handleFunction);
addCollectionHandler(Method::POST, "/[^_][^/]*/_query", &RESTListener::handleQuery);

// Document:
addCollectionHandler(Method::GET, "/[^_][^/]*/[^_].*", &RESTListener::handleGetDoc);
Expand Down
2 changes: 2 additions & 0 deletions REST/RESTListener.hh
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ namespace litecore::REST {
void handleModifyDoc(RequestResponse&, C4Collection*);
void handleBulkDocs(RequestResponse&, C4Collection*);
void handleChanges(RequestResponse&, C4Collection*);
void handleFunction(RequestResponse&, C4Collection*);
void handleQuery(RequestResponse&, C4Collection*);

bool modifyDoc(fleece::Dict body, std::string docID, const std::string& revIDQuery, bool deleting,
bool newEdits, C4Collection* coll, fleece::JSONEncoder& json, C4Error* outError) noexcept;
Expand Down

0 comments on commit 5be8e84

Please sign in to comment.