gesel
Validating Gesel database files
Loading...
Searching...
No Matches
validate_genes.hpp
Go to the documentation of this file.
1#ifndef GESEL_VALIDATE_GENES_HPP
2#define GESEL_VALIDATE_GENES_HPP
3
4#include "check_genes.hpp"
5#include "check_version.hpp"
6#include "utils.hpp"
7
8#include <cstdint>
9#include <string>
10#include <vector>
11#include <stdexcept>
12#include <filesystem>
13
19namespace gesel {
20
35inline std::uint64_t validate_genes(const std::string& prefix, const std::vector<std::string>& types) {
36 bool first = true;
37 uint64_t num_genes = 0;
38 for (auto t : types) {
39 auto candidate = internal::check_genes(prefix + t + ".tsv.gz");
40 if (first) {
41 num_genes = candidate;
42 first = false;
43 } else if (candidate != num_genes) {
44 throw std::runtime_error("inconsistent number of genes between types (" + std::to_string(num_genes) + " for " + types.front() + ", " + std::to_string(candidate) + " for " + t + ")");
45 }
46 }
47
48 if (first) {
49 throw std::runtime_error("at least one gene name type should be present");
50 }
51
52 return num_genes;
53}
54
66inline std::uint64_t validate_genes(const std::string& prefix) {
67 const std::string vpath = prefix + "gene-version.tsv";
68 internal::Version version;
69 if (std::filesystem::exists(vpath)) {
70 version = internal::check_version(vpath);
71 }
72
73 std::vector<std::string> types;
74 if (version < internal::Version(0, 2, 0)) {
75 // For version 0.1.*, the available types is inferred from the available files in the directory.
76 // This is kinda fragile as it assumes that no other files start with 'prefix',
77 // so you can't really mix the gene files with the database files.
78 // It's also hard to query for the available types if the files aren't already on your filesystem.
79 std::filesystem::path path(prefix);
80 auto dir = path.parent_path();
81 auto raw_prefix = path.filename().string();
82
83 for (const auto& entry : std::filesystem::directory_iterator(dir)) {
84 std::string name = entry.path().filename().string();
85 if (name.rfind(raw_prefix, 0) != 0) {
86 continue;
87 }
88 if (name.size() < 6) {
89 continue;
90 }
91 size_t ext_loc = name.size() - 7;
92 if (name.rfind(".tsv.gz", ext_loc) != ext_loc) {
93 continue;
94 }
95 types.push_back(name.substr(raw_prefix.size(), ext_loc - raw_prefix.size()));
96 }
97
98 return validate_genes(prefix, types);
99
100 } else {
101 // For versions at or above 0.2.0, we use a dedicated 'gene-types.tsv' file to specify the available types.
102 // This can be easily consulted to figure out the available types.
103 // Each file is also prefixed with 'gene-type-' to avoid conflicts with Gesel database files.
104 const auto manifest_path = prefix + "gene-types.tsv";
105 byteme::RawFileReader reader(manifest_path.c_str(), {});
106 byteme::SerialBufferedReader<char, internal::I<decltype(&reader)> > pb(&reader, 65536);
107 if (!pb.valid()) {
108 throw std::runtime_error("expected at least one gene identifier type in '" + manifest_path + "'");
109 }
110
111 while (1) {
112 std::string type;
113 char current = pb.get();
114 while (current != '\n') {
115 if ((current >= 'a' && current <= 'z') || (current >= 'A' && current <= 'Z') || (current >= '0' && current <= '9')) {
116 type += current;
117 } else {
118 throw std::runtime_error("gene identifier type should only contain alphanumeric characters in '" + manifest_path + "'");
119 }
120 if (!pb.advance()) {
121 throw std::runtime_error("premature termination of gene identifier type in '" + manifest_path + "'");
122 }
123 current = pb.get();
124 }
125
126 if (type.size() == 0) {
127 throw std::runtime_error("empty gene identifier type in '" + manifest_path + "'");
128 }
129 types.push_back(std::move(type));
130
131 if (!pb.advance()) {
132 break;
133 }
134 }
135
136 return validate_genes(prefix + "gene-type-", types);
137 }
138}
139
140}
141
142#endif
Validate Gesel-related file formats.
Definition validate_database.hpp:20
std::uint64_t validate_genes(const std::string &prefix, const std::vector< std::string > &types)
Definition validate_genes.hpp:35