Skip to content

Commit

Permalink
feat: add endpoint that returns the lineageDefinitions for the reques…
Browse files Browse the repository at this point in the history
…ted column (#689)
  • Loading branch information
Taepper committed Feb 6, 2025
1 parent edd23d2 commit 69cd9b0
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 1 deletion.
48 changes: 48 additions & 0 deletions endToEndTests/test/lineageDefinition.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { expectHeaderToHaveDataVersion, server } from './common.js';
import { describe, it } from 'node:test';
import { expect } from 'chai';

describe('The /lineageDefinition endpoint', () => {
it('should return the lineage index', async () => {
let searchString = `A: \{\}
A.1:
parents:
- A
A.11:
parents:
- A
`;
await server
.get('/lineageDefinition/pango_lineage')
.expect(200)
.expect('Content-Type', 'application/yaml')
.expect(expectHeaderToHaveDataVersion)
.then(response => {
expect(response.text).to.match(new RegExp(`^${searchString}`));
});
});

it('should return an error for column name that is not present', async () => {
await server
.get('/lineageDefinition/columnThatIsNotPresent')
.expect(400)
.expect('Content-Type', 'application/json')
.expect(expectHeaderToHaveDataVersion)
.then(response => {
expect(response.body.message).to.equal(
'The column columnThatIsNotPresent does not exist in this instance.'
);
});
});

it('should return an error for column name that does not have a lineage index', async () => {
await server
.get('/lineageDefinition/country')
.expect(400)
.expect('Content-Type', 'application/json')
.expect(expectHeaderToHaveDataVersion)
.then(response => {
expect(response.body.message).to.equal('The column country does not have a lineageIndex defined.');
});
});
});
23 changes: 23 additions & 0 deletions include/silo/api/lineage_definition_handler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

#include <Poco/Net/HTTPServerRequest.h>
#include <Poco/Net/HTTPServerResponse.h>

#include "database_mutex.h"
#include "rest_resource.h"

namespace silo::api {

class LineageDefinitionHandler : public RestResource {
private:
DatabaseMutex& database;
std::string column_name;

public:
explicit LineageDefinitionHandler(DatabaseMutex& database, std::string column_name);

void get(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
override;
};

} // namespace silo::api
2 changes: 1 addition & 1 deletion include/silo/database.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class Database {

public:
silo::config::DatabaseConfig database_config;
common::LineageTreeAndIdMap lineage_tree;
std::vector<DatabasePartition> partitions;
std::filesystem::path unaligned_sequences_directory;

Expand All @@ -47,7 +48,6 @@ class Database {
std::map<std::string, UnalignedSequenceStore> unaligned_nuc_sequences;

private:
common::LineageTreeAndIdMap lineage_tree;
DataVersion data_version_ = DataVersion::mineDataVersion();

public:
Expand Down
2 changes: 2 additions & 0 deletions include/silo/storage/column/indexed_string_column.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ class IndexedStringColumn {
IndexedStringColumn& operator=(IndexedStringColumn&& other) = delete;

IndexedStringColumnPartition& createPartition();

bool hasLineageTree() const;
};

} // namespace silo::storage::column
57 changes: 57 additions & 0 deletions src/silo/api/lineage_definition_handler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#include "silo/api/lineage_definition_handler.h"

#include <map>
#include <string>

#include <Poco/Net/HTTPServerRequest.h>
#include <Poco/Net/HTTPServerResponse.h>
#include <Poco/URI.h>
#include <nlohmann/json.hpp>

#include "silo/api/database_mutex.h"
#include "silo/api/error_request_handler.h"

namespace silo::api {

LineageDefinitionHandler::LineageDefinitionHandler(DatabaseMutex& database, std::string column_name)
: database(database),
column_name(std::move(column_name)) {}

void LineageDefinitionHandler::get(
Poco::Net::HTTPServerRequest& request,
Poco::Net::HTTPServerResponse& response
) {
const auto fixed_database = database.getDatabase();

response.set("data-version", fixed_database->getDataVersionTimestamp().value);

auto column_metadata =
std::ranges::find_if(fixed_database->columns.metadata, [&](const auto& metadata) {
return metadata.name == column_name;
});
if (column_metadata == fixed_database->columns.metadata.end()) {
response.setContentType("application/json");
response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
std::ostream& out_stream = response.send();
out_stream << nlohmann::json(ErrorResponse{
.error = "Bad request",
.message = fmt::format("The column {} does not exist in this instance.", column_name)
});
}
// TODO(#691) Change this check for containment to a selection of the correct lineage system
else if(column_metadata->type != config::ColumnType::INDEXED_STRING || !fixed_database->columns.indexed_string_columns.at(column_name).hasLineageTree()){
response.setContentType("application/json");
response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
std::ostream& out_stream = response.send();
out_stream << nlohmann::json(ErrorResponse{
.error = "Bad request",
.message = fmt::format("The column {} does not have a lineageIndex defined.", column_name)
});
} else {
const std::string lineage_definition_yaml = fixed_database->lineage_tree.file;
response.setContentType("application/yaml");
std::ostream& out_stream = response.send();
out_stream << lineage_definition_yaml;
}
}
} // namespace silo::api
7 changes: 7 additions & 0 deletions src/silo/api/request_handler_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "silo/api/error_request_handler.h"
#include "silo/api/info_handler.h"
#include "silo/api/lineage_definition_handler.h"
#include "silo/api/logging_request_handler.h"
#include "silo/api/not_found_handler.h"
#include "silo/api/query_handler.h"
Expand Down Expand Up @@ -35,9 +36,15 @@ std::unique_ptr<Poco::Net::HTTPRequestHandler> SiloRequestHandlerFactory::routeR
) {
const auto& uri = Poco::URI(request.getURI());
const auto path = uri.getPath();
std::vector<std::string> segments;
uri.getPathSegments(segments);

if (path == "/info") {
return std::make_unique<silo::api::InfoHandler>(database);
}
if (segments.size() == 2 && segments.at(0) == "lineageDefinition") {
return std::make_unique<silo::api::LineageDefinitionHandler>(database, segments.at(1));
}
if (path == "/query") {
return std::make_unique<silo::api::QueryHandler>(database);
}
Expand Down
4 changes: 4 additions & 0 deletions src/silo/storage/column/indexed_string_column.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,8 @@ IndexedStringColumnPartition& IndexedStringColumn::createPartition() {
return partitions.emplace_back(IndexedStringColumnPartition{column_name, &lookup});
}

bool IndexedStringColumn::hasLineageTree() const {
return lineage_tree.has_value();
}

} // namespace silo::storage::column

0 comments on commit 69cd9b0

Please sign in to comment.