Delete import and serialisation
Reviewers: buda Reviewed By: buda Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D294
This commit is contained in:
parent
5434e79ea6
commit
d42d519956
@ -1,172 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <chrono>
|
|
||||||
#include <cstring>
|
|
||||||
#include <ctime>
|
|
||||||
#include <fstream>
|
|
||||||
#include <iostream>
|
|
||||||
#include <queue>
|
|
||||||
#include <regex>
|
|
||||||
#include <sstream>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "import/element_skeleton.hpp"
|
|
||||||
#include "import/fillings/filler.hpp"
|
|
||||||
#include "logging/default.hpp"
|
|
||||||
#include "storage/model/properties/flags.hpp"
|
|
||||||
#include "storage/vertex_accessor.hpp"
|
|
||||||
#include "utils/option.hpp"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
static Option<VertexAccessor> empty_op_vacc;
|
|
||||||
|
|
||||||
// Base importer with common facilities.
|
|
||||||
class BaseImporter {
|
|
||||||
public:
|
|
||||||
BaseImporter(DbAccessor &db, Logger &&logger)
|
|
||||||
: db(db), logger(std::move(logger)) {}
|
|
||||||
|
|
||||||
char *cstr(string &str) { return &str[0]; }
|
|
||||||
|
|
||||||
bool split(string &str, char mark, vector<char *> &sub_str) {
|
|
||||||
return split(cstr(str), mark, sub_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Occurances of mark are changed with '\0'. sub_str is filled with
|
|
||||||
// pointers to parts of str splited by mark in ascending order. Empty
|
|
||||||
// sub_str are included. Doesn't split inside quotations and
|
|
||||||
// open_bracket,closed_bracket.
|
|
||||||
// Returns true if it was succesfully parsed.
|
|
||||||
bool split(char *str, char mark, vector<char *> &sub_str) {
|
|
||||||
int head = 0;
|
|
||||||
bool in_text = false;
|
|
||||||
bool in_array = false;
|
|
||||||
|
|
||||||
for (int i = 0; str[i] != '\0'; i++) {
|
|
||||||
char &c = str[i];
|
|
||||||
|
|
||||||
// IN TEXT check
|
|
||||||
if (c == quotations_mark) {
|
|
||||||
in_text = !in_text;
|
|
||||||
if (in_text && head == i) {
|
|
||||||
c = '\0';
|
|
||||||
head = i + 1;
|
|
||||||
} else if (!in_text && !in_array) {
|
|
||||||
c = '\0';
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
} else if (in_text) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// IN ARRAY check
|
|
||||||
if (c == open_bracket) {
|
|
||||||
if (in_array) {
|
|
||||||
logger.error("Nested arrays aren't supported.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
in_array = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (in_array) {
|
|
||||||
if (c == closed_bracket) {
|
|
||||||
in_array = false;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SPLIT CHECK
|
|
||||||
if (c == mark) {
|
|
||||||
c = '\0';
|
|
||||||
sub_str.push_back(&str[head]);
|
|
||||||
head = i + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub_str.push_back(&str[head]);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extracts parts of str while stripping parts of array chars and qutation
|
|
||||||
// marks. Parts are separated with delimiter.
|
|
||||||
void extract(char *str, const char delimiter, vector<char *> &sub_str) {
|
|
||||||
int head = 0;
|
|
||||||
bool in_text = false;
|
|
||||||
|
|
||||||
for (int i = 0; str[i] != '\0'; i++) {
|
|
||||||
char &c = str[i];
|
|
||||||
|
|
||||||
// IN TEXT check
|
|
||||||
if (c == quotations_mark) {
|
|
||||||
in_text = !in_text;
|
|
||||||
if (in_text) {
|
|
||||||
} else {
|
|
||||||
c = '\0';
|
|
||||||
sub_str.push_back(&str[head]);
|
|
||||||
head = i + 1;
|
|
||||||
}
|
|
||||||
head = i + 1;
|
|
||||||
continue;
|
|
||||||
} else if (in_text) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// IN ARRAY check
|
|
||||||
if (c == open_bracket) {
|
|
||||||
head = i + 1;
|
|
||||||
continue;
|
|
||||||
} else if (c == closed_bracket) {
|
|
||||||
c = '\0';
|
|
||||||
if (i > head) {
|
|
||||||
sub_str.push_back(&str[head]);
|
|
||||||
}
|
|
||||||
head = i + 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SPLIT CHECK
|
|
||||||
if (c == delimiter) {
|
|
||||||
c = '\0';
|
|
||||||
if (i > head) {
|
|
||||||
sub_str.push_back(&str[head]);
|
|
||||||
}
|
|
||||||
head = i + 1;
|
|
||||||
} else if (c == ' ' && i == head) {
|
|
||||||
head++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub_str.push_back(&str[head]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optionaly return vertex with given import local id if it exists.
|
|
||||||
Option<VertexAccessor> const &get_vertex(size_t id) {
|
|
||||||
if (vertices.size() > id) {
|
|
||||||
return vertices[id];
|
|
||||||
} else {
|
|
||||||
cout << vertices.size() << " -> " << id << endl;
|
|
||||||
return empty_op_vacc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
DbAccessor &db;
|
|
||||||
Logger logger;
|
|
||||||
|
|
||||||
// Varius marks and delimiters. They can be freely changed here and
|
|
||||||
// everything will work.
|
|
||||||
char parts_mark = ',';
|
|
||||||
char parts_array_mark = ',';
|
|
||||||
char type_mark = ':';
|
|
||||||
char quotations_mark = '"';
|
|
||||||
char open_bracket = '[';
|
|
||||||
char closed_bracket = ']';
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// All created vertices which have import local id.
|
|
||||||
vector<Option<VertexAccessor>> vertices;
|
|
||||||
};
|
|
@ -1,400 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <chrono>
|
|
||||||
#include <cstring>
|
|
||||||
#include <ctime>
|
|
||||||
#include <fstream>
|
|
||||||
#include <iostream>
|
|
||||||
#include <queue>
|
|
||||||
#include <regex>
|
|
||||||
#include <sstream>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "import/base_import.hpp"
|
|
||||||
#include "import/element_skeleton.hpp"
|
|
||||||
#include "import/fillings/array.hpp"
|
|
||||||
#include "import/fillings/bool.hpp"
|
|
||||||
#include "import/fillings/double.hpp"
|
|
||||||
#include "import/fillings/filler.hpp"
|
|
||||||
#include "import/fillings/float.hpp"
|
|
||||||
#include "import/fillings/from.hpp"
|
|
||||||
#include "import/fillings/id.hpp"
|
|
||||||
#include "import/fillings/int32.hpp"
|
|
||||||
#include "import/fillings/int64.hpp"
|
|
||||||
#include "import/fillings/label.hpp"
|
|
||||||
#include "import/fillings/skip.hpp"
|
|
||||||
#include "import/fillings/string.hpp"
|
|
||||||
#include "import/fillings/to.hpp"
|
|
||||||
#include "import/fillings/type.hpp"
|
|
||||||
#include "storage/model/properties/all.hpp"
|
|
||||||
#include "storage/model/properties/flags.hpp"
|
|
||||||
#include "storage/vertex_accessor.hpp"
|
|
||||||
#include "utils/assert.hpp"
|
|
||||||
#include "utils/command_line/arguments.hpp"
|
|
||||||
#include "utils/option.hpp"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
constexpr char const *_string = "string";
|
|
||||||
|
|
||||||
// Will change all int32 into int64, and all float into double from csv into
|
|
||||||
// database. Uplifting will occure even in arrays.
|
|
||||||
constexpr const bool UPLIFT_PRIMITIVES = true;
|
|
||||||
|
|
||||||
bool equal_str(const char *a, const char *b) { return strcasecmp(a, b) == 0; }
|
|
||||||
|
|
||||||
// CSV importer for importing multiple files regarding same graph.
|
|
||||||
// CSV format of file should be following:
|
|
||||||
// header
|
|
||||||
// line of data
|
|
||||||
// line of data
|
|
||||||
// ...
|
|
||||||
//
|
|
||||||
// Where header should be composed of parts splited by parts_mark. Number of
|
|
||||||
// parts should be same as number of parts in every line of data. Parts should
|
|
||||||
// be of format name:type where name is alfanumeric identifyer of data in thath
|
|
||||||
// column and type should be one of: id, from, to, label, type, bool, int, long,
|
|
||||||
// float, double, string, bool[], int[], long[], float[], double[], string[].
|
|
||||||
// If name is missing the column data wont be saved into the elements.
|
|
||||||
// if the type is missing the column will be interperted as type string. If
|
|
||||||
// neither name nor type are present column will be skipped.
|
|
||||||
class CSVImporter : public BaseImporter {
|
|
||||||
public:
|
|
||||||
CSVImporter(DbAccessor &db)
|
|
||||||
: BaseImporter(db, logging::log->logger("CSV_import")) {}
|
|
||||||
|
|
||||||
// Loads data from stream and returns number of loaded vertexes.
|
|
||||||
size_t import_vertices(std::fstream &file) {
|
|
||||||
return import<TypeGroupVertex>(file, create_vertex, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loads data from stream and returns number of loaded edges.
|
|
||||||
size_t import_edges(std::fstream &file) {
|
|
||||||
return import<TypeGroupEdge>(file, create_edge, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Loads data from file and returns number of loaded name.
|
|
||||||
// TG - TypeGroup
|
|
||||||
// F - function which will create element from filled element skelleton.
|
|
||||||
template <class TG, class F>
|
|
||||||
size_t import(std::fstream &file, F f, bool vertex) {
|
|
||||||
string line;
|
|
||||||
vector<char *> sub_str;
|
|
||||||
vector<unique_ptr<Filler>> fillers;
|
|
||||||
vector<char *> tmp;
|
|
||||||
|
|
||||||
// HEADERS
|
|
||||||
if (!getline(file, line)) {
|
|
||||||
logger.error("No lines");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!split(line, parts_mark, sub_str)) {
|
|
||||||
logger.error("Illegal headers");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto p : sub_str) {
|
|
||||||
auto o = get_filler<TG>(p, tmp, vertex);
|
|
||||||
if (o.is_present()) {
|
|
||||||
fillers.push_back(o.take());
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sub_str.clear();
|
|
||||||
|
|
||||||
// LOAD DATA LINES
|
|
||||||
size_t count = 0;
|
|
||||||
size_t line_no = 1;
|
|
||||||
ElementSkeleton es(db);
|
|
||||||
while (std::getline(file, line)) {
|
|
||||||
sub_str.clear();
|
|
||||||
es.clear();
|
|
||||||
|
|
||||||
if (split(line, parts_mark, sub_str)) {
|
|
||||||
check_for_part_count(sub_str.size() - fillers.size(), line_no);
|
|
||||||
|
|
||||||
int n = min(sub_str.size(), fillers.size());
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
auto er = fillers[i]->fill(es, sub_str[i]);
|
|
||||||
if (er.is_present()) {
|
|
||||||
logger.error("{} on line: {}", er.get(), line_no);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f(this, es, line_no)) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
line_no++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool create_vertex(CSVImporter *im, ElementSkeleton &es,
|
|
||||||
size_t line_no) {
|
|
||||||
auto va = es.add_vertex();
|
|
||||||
auto id = es.element_id();
|
|
||||||
if (id.is_present()) {
|
|
||||||
if (im->vertices.size() <= id.get()) {
|
|
||||||
Option<VertexAccessor> empty = make_option<VertexAccessor>();
|
|
||||||
im->vertices.insert(im->vertices.end(),
|
|
||||||
id.get() - im->vertices.size() + 1, empty);
|
|
||||||
}
|
|
||||||
if (im->vertices[id.get()].is_present()) {
|
|
||||||
im->logger.error(
|
|
||||||
"Vertex on line: {} has same id with another "
|
|
||||||
"previously loaded vertex",
|
|
||||||
line_no);
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
im->vertices[id.get()] = make_option(std::move(va));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
im->logger.warn(
|
|
||||||
"Missing import local vertex id for vertex on "
|
|
||||||
"line: {}",
|
|
||||||
line_no);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool create_edge(CSVImporter *im, ElementSkeleton &es,
|
|
||||||
size_t line_no) {
|
|
||||||
auto o = es.add_edge();
|
|
||||||
if (!o.is_present()) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
im->logger.error("{} on line: {}", o.get(), line_no);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class TG>
|
|
||||||
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey property_key(
|
|
||||||
const char *name, Flags type) {
|
|
||||||
debug_assert(false, "Fail.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns filler for name:type in header_part. None if error occured.
|
|
||||||
template <class TG>
|
|
||||||
Option<unique_ptr<Filler>> get_filler(char *header_part,
|
|
||||||
vector<char *> &tmp_vec, bool vertex) {
|
|
||||||
tmp_vec.clear();
|
|
||||||
split(header_part, type_mark, tmp_vec);
|
|
||||||
|
|
||||||
const char *name = tmp_vec[0];
|
|
||||||
const char *type = tmp_vec[1];
|
|
||||||
|
|
||||||
if (tmp_vec.size() > 2) {
|
|
||||||
logger.error("To much sub parts in header part");
|
|
||||||
return make_option<unique_ptr<Filler>>();
|
|
||||||
|
|
||||||
} else if (tmp_vec.size() < 2) {
|
|
||||||
if (tmp_vec.size() == 1) {
|
|
||||||
logger.warn(
|
|
||||||
"Column: {} doesn't have specified type so string "
|
|
||||||
"type will be used",
|
|
||||||
tmp_vec[0]);
|
|
||||||
name = tmp_vec[0];
|
|
||||||
type = _string;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
logger.warn("Empty colum definition, skiping column.");
|
|
||||||
std::unique_ptr<Filler> f(new SkipFiller());
|
|
||||||
return make_option(std::move(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
name = tmp_vec[0];
|
|
||||||
type = tmp_vec[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create adequat filler
|
|
||||||
if (equal_str(type, "id")) {
|
|
||||||
std::unique_ptr<Filler> f(
|
|
||||||
name[0] == '\0' ? new IdFiller<TG>()
|
|
||||||
: new IdFiller<TG>(make_option(
|
|
||||||
property_key<TG>(name, Flags::Int64))));
|
|
||||||
return make_option(std::move(f));
|
|
||||||
|
|
||||||
} else if (equal_str(type, "start_id") || equal_str(type, "from_id") ||
|
|
||||||
equal_str(type, "from") || equal_str(type, "source")) {
|
|
||||||
std::unique_ptr<Filler> f(new FromFiller(*this));
|
|
||||||
return make_option(std::move(f));
|
|
||||||
|
|
||||||
} else if (equal_str(type, "label")) {
|
|
||||||
std::unique_ptr<Filler> f(new LabelFiller(*this));
|
|
||||||
return make_option(std::move(f));
|
|
||||||
|
|
||||||
} else if (equal_str(type, "end_id") || equal_str(type, "to_id") ||
|
|
||||||
equal_str(type, "to") || equal_str(type, "target")) {
|
|
||||||
std::unique_ptr<Filler> f(new ToFiller(*this));
|
|
||||||
return make_option(std::move(f));
|
|
||||||
|
|
||||||
} else if (equal_str(type, "type")) {
|
|
||||||
std::unique_ptr<Filler> f(new TypeFiller(*this));
|
|
||||||
return make_option(std::move(f));
|
|
||||||
|
|
||||||
} else if (name[0] == '\0') { // OTHER FILLERS REQUIRE NAME
|
|
||||||
logger.warn("Unnamed column of type: {} will be skipped.", type);
|
|
||||||
std::unique_ptr<Filler> f(new SkipFiller());
|
|
||||||
return make_option(std::move(f));
|
|
||||||
|
|
||||||
// *********************** PROPERTIES
|
|
||||||
} else if (equal_str(type, "bool")) {
|
|
||||||
std::unique_ptr<Filler> f(
|
|
||||||
new BoolFiller<TG>(property_key<TG>(name, Flags::Bool)));
|
|
||||||
return make_option(std::move(f));
|
|
||||||
|
|
||||||
} else if (equal_str(type, "double") ||
|
|
||||||
(UPLIFT_PRIMITIVES && equal_str(type, "float"))) {
|
|
||||||
std::unique_ptr<Filler> f(
|
|
||||||
new DoubleFiller<TG>(property_key<TG>(name, Flags::Double)));
|
|
||||||
return make_option(std::move(f));
|
|
||||||
|
|
||||||
} else if (equal_str(type, "float")) {
|
|
||||||
std::unique_ptr<Filler> f(
|
|
||||||
new FloatFiller<TG>(property_key<TG>(name, Flags::Float)));
|
|
||||||
return make_option(std::move(f));
|
|
||||||
|
|
||||||
} else if (equal_str(type, "long") ||
|
|
||||||
(UPLIFT_PRIMITIVES && equal_str(type, "int"))) {
|
|
||||||
std::unique_ptr<Filler> f(
|
|
||||||
new Int64Filler<TG>(property_key<TG>(name, Flags::Int64)));
|
|
||||||
return make_option(std::move(f));
|
|
||||||
|
|
||||||
} else if (equal_str(type, "int")) {
|
|
||||||
std::unique_ptr<Filler> f(
|
|
||||||
new Int32Filler<TG>(property_key<TG>(name, Flags::Int32)));
|
|
||||||
return make_option(std::move(f));
|
|
||||||
|
|
||||||
} else if (equal_str(type, "string")) {
|
|
||||||
std::unique_ptr<Filler> f(
|
|
||||||
new StringFiller<TG>(property_key<TG>(name, Flags::String)));
|
|
||||||
return make_option(std::move(f));
|
|
||||||
|
|
||||||
} else if (equal_str(type, "bool[]")) {
|
|
||||||
std::unique_ptr<Filler> f(make_array_filler<TG, bool, ArrayBool>(
|
|
||||||
*this, property_key<TG>(name, Flags::ArrayBool), to_bool));
|
|
||||||
return make_option(std::move(f));
|
|
||||||
|
|
||||||
} else if (equal_str(type, "double[]") ||
|
|
||||||
(UPLIFT_PRIMITIVES && equal_str(type, "float[]"))) {
|
|
||||||
std::unique_ptr<Filler> f(make_array_filler<TG, double, ArrayDouble>(
|
|
||||||
*this, property_key<TG>(name, Flags::ArrayDouble), to_double));
|
|
||||||
return make_option(std::move(f));
|
|
||||||
|
|
||||||
} else if (equal_str(type, "float[]")) {
|
|
||||||
std::unique_ptr<Filler> f(make_array_filler<TG, float, ArrayFloat>(
|
|
||||||
*this, property_key<TG>(name, Flags::ArrayFloat), to_float));
|
|
||||||
return make_option(std::move(f));
|
|
||||||
|
|
||||||
} else if (equal_str(type, "long[]") ||
|
|
||||||
(UPLIFT_PRIMITIVES && equal_str(type, "int[]"))) {
|
|
||||||
std::unique_ptr<Filler> f(make_array_filler<TG, int64_t, ArrayInt64>(
|
|
||||||
*this, property_key<TG>(name, Flags::ArrayInt64), to_int64));
|
|
||||||
return make_option(std::move(f));
|
|
||||||
|
|
||||||
} else if (equal_str(type, "int[]")) {
|
|
||||||
std::unique_ptr<Filler> f(make_array_filler<TG, int32_t, ArrayInt32>(
|
|
||||||
*this, property_key<TG>(name, Flags::ArrayInt32), to_int32));
|
|
||||||
return make_option(std::move(f));
|
|
||||||
|
|
||||||
} else if (equal_str(type, "string[]")) {
|
|
||||||
std::unique_ptr<Filler> f(make_array_filler<TG, std::string, ArrayString>(
|
|
||||||
*this, property_key<TG>(name, Flags::ArrayString), to_string));
|
|
||||||
return make_option(std::move(f));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
logger.error("Unknown type: {}", type);
|
|
||||||
return make_option<unique_ptr<Filler>>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void check_for_part_count(long diff, long line_no) {
|
|
||||||
if (diff != 0) {
|
|
||||||
if (diff < 0) {
|
|
||||||
logger.warn(
|
|
||||||
"Line no: {} has less parts then specified in "
|
|
||||||
"header. Missing: {} parts",
|
|
||||||
line_no, diff);
|
|
||||||
} else {
|
|
||||||
logger.warn(
|
|
||||||
"Line no: {} has more parts then specified in "
|
|
||||||
"header. Extra: {} parts",
|
|
||||||
line_no, diff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
PropertyFamily<TypeGroupVertex>::PropertyType::PropertyFamilyKey
|
|
||||||
CSVImporter::property_key<TypeGroupVertex>(const char *name, Flags type) {
|
|
||||||
return db.vertex_property_key(name, Type(type));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
PropertyFamily<TypeGroupEdge>::PropertyType::PropertyFamilyKey
|
|
||||||
CSVImporter::property_key<TypeGroupEdge>(const char *name, Flags type) {
|
|
||||||
return db.edge_property_key(name, Type(type));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Imports all -v "vertex_file_path.csv" vertices and -e "edge_file_path.csv"
|
|
||||||
// edges from specified files. Also defines arguments -d, -ad.
|
|
||||||
// -d delimiter => sets delimiter for parsing .csv files. Default is ,
|
|
||||||
// -ad delimiter => sets delimiter for parsing arrays in .csv. Default is
|
|
||||||
// Returns (no loaded vertices,no loaded edges)
|
|
||||||
std::pair<size_t, size_t> import_csv_from_arguments(
|
|
||||||
Db &db, std::vector<std::string> ¶) {
|
|
||||||
DbAccessor t(db);
|
|
||||||
CSVImporter imp(t);
|
|
||||||
|
|
||||||
imp.parts_mark = get_argument(para, "-d", ",")[0];
|
|
||||||
imp.parts_array_mark = get_argument(para, "-ad", ",")[0];
|
|
||||||
|
|
||||||
// IMPORT VERTICES
|
|
||||||
size_t l_v = 0;
|
|
||||||
auto o = take_argument(para, "-v");
|
|
||||||
while (o.is_present()) {
|
|
||||||
std::fstream file(o.get());
|
|
||||||
|
|
||||||
imp.logger.info("Importing vertices from file: {}", o.get());
|
|
||||||
|
|
||||||
auto n = imp.import_vertices(file);
|
|
||||||
l_v = +n;
|
|
||||||
|
|
||||||
imp.logger.info("Loaded: {} vertices from {}", n, o.get());
|
|
||||||
|
|
||||||
o = take_argument(para, "-v");
|
|
||||||
}
|
|
||||||
|
|
||||||
// IMPORT EDGES
|
|
||||||
size_t l_e = 0;
|
|
||||||
o = take_argument(para, "-e");
|
|
||||||
while (o.is_present()) {
|
|
||||||
std::fstream file(o.get());
|
|
||||||
|
|
||||||
imp.logger.info("Importing edges from file: {}", o.get());
|
|
||||||
|
|
||||||
auto n = imp.import_edges(file);
|
|
||||||
l_e = +n;
|
|
||||||
|
|
||||||
imp.logger.info("Loaded: {} edges from {}", n, o.get());
|
|
||||||
|
|
||||||
o = take_argument(para, "-e");
|
|
||||||
}
|
|
||||||
|
|
||||||
t.commit();
|
|
||||||
|
|
||||||
return std::make_pair(l_v, l_e);
|
|
||||||
}
|
|
@ -1,100 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "database/db_accessor.hpp"
|
|
||||||
#include "storage/model/property_value.hpp"
|
|
||||||
#include "storage/model/property_value_store.hpp"
|
|
||||||
#include "storage/vertex_accessor.hpp"
|
|
||||||
#include "utils/assert.hpp"
|
|
||||||
|
|
||||||
// Holder for element data which he can then insert as a vertex or edge into the
|
|
||||||
// database depending on the available data and called add_* method.
|
|
||||||
class ElementSkeleton {
|
|
||||||
public:
|
|
||||||
ElementSkeleton(DbAccessor &db) : db(db){};
|
|
||||||
|
|
||||||
void add_property(StoredProperty<TypeGroupVertex> &&prop) {
|
|
||||||
properties_v.push_back(std::move(prop));
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_property(StoredProperty<TypeGroupEdge> &&prop) {
|
|
||||||
properties_e.push_back(std::move(prop));
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_element_id(size_t id) { el_id = make_option<size_t>(std::move(id)); }
|
|
||||||
|
|
||||||
void add_label(Label const &label) { labels.push_back(&label); }
|
|
||||||
|
|
||||||
void set_type(EdgeType const &type) { this->type = make_option(&type); }
|
|
||||||
|
|
||||||
void set_from(VertexAccessor &&va) {
|
|
||||||
from_va = make_option<VertexAccessor>(std::move(va));
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_to(VertexAccessor &&va) {
|
|
||||||
to_va = make_option<VertexAccessor>(std::move(va));
|
|
||||||
}
|
|
||||||
|
|
||||||
VertexAccessor add_vertex() {
|
|
||||||
debug_assert(properties_e.empty(), "Properties aren't empty.");
|
|
||||||
|
|
||||||
auto va = db.vertex_insert();
|
|
||||||
|
|
||||||
for (auto l : labels) {
|
|
||||||
// std::cout << *l << std::endl;
|
|
||||||
va.add_label(*l);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto prop : properties_v) {
|
|
||||||
va.set(std::move(prop));
|
|
||||||
}
|
|
||||||
|
|
||||||
return va;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return error msg if unsuccessful
|
|
||||||
Option<std::string> add_edge() {
|
|
||||||
if (!from_va.is_present()) {
|
|
||||||
return make_option(std::string("From field must be set"));
|
|
||||||
}
|
|
||||||
if (!to_va.is_present()) {
|
|
||||||
return make_option(std::string("To field must be set"));
|
|
||||||
}
|
|
||||||
if (!type.is_present()) {
|
|
||||||
return make_option(std::string("Type field must be set"));
|
|
||||||
}
|
|
||||||
debug_assert(properties_v.empty(), "Properties aren't empty.");
|
|
||||||
|
|
||||||
auto ve = db.edge_insert(from_va.get(), to_va.get());
|
|
||||||
ve.edge_type(*type.get());
|
|
||||||
|
|
||||||
for (auto prop : properties_e) {
|
|
||||||
ve.set(std::move(prop));
|
|
||||||
}
|
|
||||||
|
|
||||||
return make_option<std::string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear() {
|
|
||||||
el_id = make_option<size_t>();
|
|
||||||
to_va = make_option<VertexAccessor>();
|
|
||||||
from_va = make_option<VertexAccessor>();
|
|
||||||
type = make_option<EdgeType const *>();
|
|
||||||
labels.clear();
|
|
||||||
properties_v.clear();
|
|
||||||
properties_e.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns import local id.
|
|
||||||
Option<size_t> element_id() { return el_id; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
DbAccessor &db;
|
|
||||||
|
|
||||||
Option<size_t> el_id;
|
|
||||||
Option<VertexAccessor> to_va;
|
|
||||||
Option<VertexAccessor> from_va;
|
|
||||||
Option<EdgeType const *> type;
|
|
||||||
std::vector<Label const *> labels;
|
|
||||||
PropertyValueStore properties_e;
|
|
||||||
PropertyValueStore properties_v;
|
|
||||||
};
|
|
@ -1,29 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "import/fillings/common.hpp"
|
|
||||||
#include "import/fillings/filler.hpp"
|
|
||||||
#include "storage/model/properties/all.hpp"
|
|
||||||
#include "storage/model/properties/flags.hpp"
|
|
||||||
#include "storage/model/properties/property_family.hpp"
|
|
||||||
|
|
||||||
// Parses boolean.
|
|
||||||
// TG - Type group
|
|
||||||
template <class TG>
|
|
||||||
class BoolFiller : public Filler {
|
|
||||||
public:
|
|
||||||
BoolFiller(typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key)
|
|
||||||
: key(key) {}
|
|
||||||
|
|
||||||
// Fills skeleton with data from str. Returns error description if
|
|
||||||
// error occurs.
|
|
||||||
Option<std::string> fill(ElementSkeleton &data, char *str) final {
|
|
||||||
if (str[0] != '\0') {
|
|
||||||
data.add_property(StoredProperty<TG>(Bool(to_bool(str)), key));
|
|
||||||
}
|
|
||||||
|
|
||||||
return make_option<std::string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key;
|
|
||||||
};
|
|
@ -1,24 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <strings.h>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
#include "storage/model/properties/all.hpp"
|
|
||||||
|
|
||||||
bool string2bool(const char *v) {
|
|
||||||
return strcasecmp(v, "true") == 0 || atoi(v) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool to_bool(const char *str) { return string2bool(str); }
|
|
||||||
|
|
||||||
float to_float(const char *str) { return stof(str); }
|
|
||||||
|
|
||||||
double to_double(const char *str) { return atof(str); }
|
|
||||||
|
|
||||||
int32_t to_int32(const char *str) { return atoi(str); }
|
|
||||||
|
|
||||||
int64_t to_int64(const char *str) { return atoll(str); }
|
|
||||||
|
|
||||||
std::string to_string(const char *str) { return std::string(str); }
|
|
@ -1,13 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "import/element_skeleton.hpp"
|
|
||||||
#include "utils/option.hpp"
|
|
||||||
|
|
||||||
// Common class for varius classes which accept one part from data line in
|
|
||||||
// import, parses it and adds it into element skelleton.
|
|
||||||
class Filler {
|
|
||||||
public:
|
|
||||||
// Fills skeleton with data from str. Returns error description if
|
|
||||||
// error occurs.
|
|
||||||
virtual Option<std::string> fill(ElementSkeleton &data, char *str) = 0;
|
|
||||||
};
|
|
@ -1,28 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "import/fillings/common.hpp"
|
|
||||||
#include "import/fillings/filler.hpp"
|
|
||||||
#include "storage/model/properties/all.hpp"
|
|
||||||
#include "storage/model/properties/flags.hpp"
|
|
||||||
#include "storage/model/properties/property_family.hpp"
|
|
||||||
|
|
||||||
// Parses float.
|
|
||||||
// TG - Type group
|
|
||||||
template <class TG>
|
|
||||||
class FloatFiller : public Filler {
|
|
||||||
public:
|
|
||||||
FloatFiller(typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key)
|
|
||||||
: key(key) {}
|
|
||||||
// Fills skeleton with data from str. Returns error description if
|
|
||||||
// error occurs.
|
|
||||||
Option<std::string> fill(ElementSkeleton &data, char *str) final {
|
|
||||||
if (str[0] != '\0') {
|
|
||||||
data.add_property(StoredProperty<TG>(Float(to_float(str)), key));
|
|
||||||
}
|
|
||||||
|
|
||||||
return make_option<std::string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key;
|
|
||||||
};
|
|
@ -1,34 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "import/fillings/common.hpp"
|
|
||||||
#include "import/fillings/filler.hpp"
|
|
||||||
#include "storage/model/properties/all.hpp"
|
|
||||||
#include "storage/model/properties/flags.hpp"
|
|
||||||
#include "storage/model/properties/property_family.hpp"
|
|
||||||
|
|
||||||
// Parses from id of vertex for edge.
|
|
||||||
class FromFiller : public Filler {
|
|
||||||
public:
|
|
||||||
FromFiller(BaseImporter &db) : bim(db) {}
|
|
||||||
|
|
||||||
// Fills skeleton with data from str. Returns error description if
|
|
||||||
// error occurs.
|
|
||||||
Option<std::string> fill(ElementSkeleton &data, char *str) final {
|
|
||||||
if (str[0] != '\0') {
|
|
||||||
auto id = atol(str);
|
|
||||||
Option<VertexAccessor> const &oav = bim.get_vertex(id);
|
|
||||||
if (oav.is_present()) {
|
|
||||||
data.set_from(VertexAccessor(oav.get()));
|
|
||||||
return make_option<std::string>();
|
|
||||||
} else {
|
|
||||||
return make_option(
|
|
||||||
std::string("Unknown vertex in from field with id: ") + str);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return make_option(std::string("From field must be spceified"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
BaseImporter &bim;
|
|
||||||
};
|
|
@ -1,38 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "import/fillings/filler.hpp"
|
|
||||||
#include "utils/assert.hpp"
|
|
||||||
|
|
||||||
// Parses import local Id.
|
|
||||||
// TG - Type group
|
|
||||||
template <class TG>
|
|
||||||
class IdFiller : public Filler {
|
|
||||||
public:
|
|
||||||
IdFiller()
|
|
||||||
: key(make_option<
|
|
||||||
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey>()) {}
|
|
||||||
|
|
||||||
IdFiller(
|
|
||||||
Option<typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey> key)
|
|
||||||
: key(key) {
|
|
||||||
debug_assert(
|
|
||||||
!key.is_present() || key.get().prop_type() == Type(Flags::Int64),
|
|
||||||
"Invalid key property type.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fills skeleton with data from str. Returns error description if
|
|
||||||
// error occurs.
|
|
||||||
Option<std::string> fill(ElementSkeleton &data, char *str) final {
|
|
||||||
if (str[0] != '\0') {
|
|
||||||
data.set_element_id(atol(str));
|
|
||||||
if (key.is_present()) {
|
|
||||||
data.add_property(StoredProperty<TG>(Int64(to_int64(str)), key.get()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return make_option<std::string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Option<typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey> key;
|
|
||||||
};
|
|
@ -1,28 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "import/fillings/common.hpp"
|
|
||||||
#include "import/fillings/filler.hpp"
|
|
||||||
#include "storage/model/properties/all.hpp"
|
|
||||||
#include "storage/model/properties/flags.hpp"
|
|
||||||
#include "storage/model/properties/property_family.hpp"
|
|
||||||
|
|
||||||
// Parses int64.
|
|
||||||
// TG - Type group
|
|
||||||
template <class TG>
|
|
||||||
class Int64Filler : public Filler {
|
|
||||||
public:
|
|
||||||
Int64Filler(typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key)
|
|
||||||
: key(key) {}
|
|
||||||
// Fills skeleton with data from str. Returns error description if
|
|
||||||
// error occurs.
|
|
||||||
Option<std::string> fill(ElementSkeleton &data, char *str) final {
|
|
||||||
if (str[0] != '\0') {
|
|
||||||
data.add_property(StoredProperty<TG>(Int64(to_int64(str)), key));
|
|
||||||
}
|
|
||||||
|
|
||||||
return make_option<std::string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key;
|
|
||||||
};
|
|
@ -1,27 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "database/db_accessor.hpp"
|
|
||||||
#include "import/fillings/filler.hpp"
|
|
||||||
|
|
||||||
// Parses array of labels.
|
|
||||||
class LabelFiller : public Filler {
|
|
||||||
public:
|
|
||||||
LabelFiller(BaseImporter &db) : bim(db) {}
|
|
||||||
|
|
||||||
// Fills skeleton with data from str. Returns error description if
|
|
||||||
// error occurs.
|
|
||||||
Option<std::string> fill(ElementSkeleton &data, char *str) final {
|
|
||||||
sub_str.clear();
|
|
||||||
bim.extract(str, bim.parts_array_mark, sub_str);
|
|
||||||
for (auto s : sub_str) {
|
|
||||||
if (s[0] != '\0') {
|
|
||||||
data.add_label(bim.db.label_find_or_create(s));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return make_option<std::string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
BaseImporter &bim;
|
|
||||||
vector<char *> sub_str;
|
|
||||||
};
|
|
@ -1,17 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "import/fillings/common.hpp"
|
|
||||||
#include "import/fillings/filler.hpp"
|
|
||||||
#include "storage/model/properties/all.hpp"
|
|
||||||
#include "storage/model/properties/flags.hpp"
|
|
||||||
#include "storage/model/properties/property_family.hpp"
|
|
||||||
|
|
||||||
// Skips column.
|
|
||||||
class SkipFiller : public Filler {
|
|
||||||
public:
|
|
||||||
// Fills skeleton with data from str. Returns error description if
|
|
||||||
// error occurs.
|
|
||||||
Option<std::string> fill(ElementSkeleton &data, char *str) final {
|
|
||||||
return make_option<std::string>();
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,28 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "import/fillings/common.hpp"
|
|
||||||
#include "import/fillings/filler.hpp"
|
|
||||||
#include "storage/model/properties/all.hpp"
|
|
||||||
#include "storage/model/properties/flags.hpp"
|
|
||||||
#include "storage/model/properties/property_family.hpp"
|
|
||||||
|
|
||||||
// Parses string.
|
|
||||||
// TG - Type group
|
|
||||||
template <class TG>
|
|
||||||
class StringFiller : public Filler {
|
|
||||||
public:
|
|
||||||
StringFiller(typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key)
|
|
||||||
: key(key) {}
|
|
||||||
// Fills skeleton with data from str. Returns error description if
|
|
||||||
// error occurs.
|
|
||||||
Option<std::string> fill(ElementSkeleton &data, char *str) final {
|
|
||||||
if (str[0] != '\0') {
|
|
||||||
data.add_property(StoredProperty<TG>(String(to_string(str)), key));
|
|
||||||
}
|
|
||||||
|
|
||||||
return make_option<std::string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
typename PropertyFamily<TG>::PropertyType::PropertyFamilyKey key;
|
|
||||||
};
|
|
@ -1,34 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "import/fillings/common.hpp"
|
|
||||||
#include "import/fillings/filler.hpp"
|
|
||||||
#include "storage/model/properties/all.hpp"
|
|
||||||
#include "storage/model/properties/flags.hpp"
|
|
||||||
#include "storage/model/properties/property_family.hpp"
|
|
||||||
|
|
||||||
// Parses to import local id of vertex for edge.
|
|
||||||
class ToFiller : public Filler {
|
|
||||||
public:
|
|
||||||
ToFiller(BaseImporter &db) : bim(db) {}
|
|
||||||
|
|
||||||
// Fills skeleton with data from str. Returns error description if
|
|
||||||
// error occurs.
|
|
||||||
Option<std::string> fill(ElementSkeleton &data, char *str) final {
|
|
||||||
if (str[0] != '\0') {
|
|
||||||
auto id = atol(str);
|
|
||||||
Option<VertexAccessor> const &oav = bim.get_vertex(id);
|
|
||||||
if (oav.is_present()) {
|
|
||||||
data.set_to(VertexAccessor(oav.get()));
|
|
||||||
return make_option<std::string>();
|
|
||||||
} else {
|
|
||||||
return make_option(std::string("Unknown vertex in to field with id: ") +
|
|
||||||
str);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return make_option(std::string("To field must be spceified"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
BaseImporter &bim;
|
|
||||||
};
|
|
@ -1,23 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "database/db_accessor.hpp"
|
|
||||||
#include "import/fillings/filler.hpp"
|
|
||||||
|
|
||||||
// Parses type of edge.
|
|
||||||
class TypeFiller : public Filler {
|
|
||||||
public:
|
|
||||||
TypeFiller(BaseImporter &db) : bim(db) {}
|
|
||||||
|
|
||||||
// Fills skeleton with data from str. Returns error description if
|
|
||||||
// error occurs.
|
|
||||||
Option<std::string> fill(ElementSkeleton &data, char *str) final {
|
|
||||||
if (str[0] != '\0') {
|
|
||||||
data.set_type(bim.db.type_find_or_create(str));
|
|
||||||
}
|
|
||||||
|
|
||||||
return make_option<std::string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
BaseImporter &bim;
|
|
||||||
};
|
|
@ -1,46 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "utils/array_store.hpp"
|
|
||||||
#include "utils/void.hpp"
|
|
||||||
|
|
||||||
// Common menthods for translating Vertex/Edge representations from serialized
|
|
||||||
// form into database form.
|
|
||||||
// Implementor should override those methods which he needs, and ignore the
|
|
||||||
// rest.
|
|
||||||
// Caller is responisble to structure his calls as following:
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// End goal would be to enforce these rules during compile time.
|
|
||||||
class GraphDecoder {
|
|
||||||
public:
|
|
||||||
// Starts reading vertex.
|
|
||||||
Id vertex_start();
|
|
||||||
|
|
||||||
// Returns number of stored labels.
|
|
||||||
size_t label_count();
|
|
||||||
|
|
||||||
// Wiil read label into given storage.
|
|
||||||
std::string const &label();
|
|
||||||
|
|
||||||
// Ends reading vertex
|
|
||||||
void vertex_end() {}
|
|
||||||
|
|
||||||
// Starts reading edge. Return from to ids of connected vertices.
|
|
||||||
std::pair<Id, Id> edge_start();
|
|
||||||
|
|
||||||
// Reads edge_type into given storage.
|
|
||||||
std::string const &edge_type();
|
|
||||||
|
|
||||||
// Ends reading edge.
|
|
||||||
void edge_end() {}
|
|
||||||
|
|
||||||
// Returns number of stored propertys.
|
|
||||||
size_t property_count();
|
|
||||||
|
|
||||||
// Reads property name into given storage.
|
|
||||||
std::string const &property_name();
|
|
||||||
|
|
||||||
// Reads property and calls T::handle for that property .
|
|
||||||
template <class T>
|
|
||||||
T property();
|
|
||||||
};
|
|
@ -1,81 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "utils/array_store.hpp"
|
|
||||||
#include "utils/void.hpp"
|
|
||||||
|
|
||||||
// Common menthods for translating Vertex/Edge representations in database to
|
|
||||||
// other format for extern usage.
|
|
||||||
// Implementor should override those methods which he needs, and ignore the
|
|
||||||
// rest.
|
|
||||||
// Caller is responisble to structure his calls as following:
|
|
||||||
// * start_vertex
|
|
||||||
// 1 label_count
|
|
||||||
// * label
|
|
||||||
// 1 property_count
|
|
||||||
// * property_name
|
|
||||||
// 1 handle
|
|
||||||
// 1 end_vertex
|
|
||||||
// or
|
|
||||||
// * start_edge
|
|
||||||
// 0-1 edge_type
|
|
||||||
// 1 property_count
|
|
||||||
// * property_name
|
|
||||||
// 1 handle
|
|
||||||
// 1 end_edge
|
|
||||||
//
|
|
||||||
// End goal would be to enforce these rules during compile time.
|
|
||||||
class GraphEncoder {
|
|
||||||
public:
|
|
||||||
// Starts writing vertex with given id.
|
|
||||||
void start_vertex(Id id) {}
|
|
||||||
|
|
||||||
// Number of following label calls.
|
|
||||||
void label_count(size_t n);
|
|
||||||
|
|
||||||
// Label of currently started vertex.
|
|
||||||
void label(std::string const &l) {}
|
|
||||||
|
|
||||||
// Ends writing vertex
|
|
||||||
void end_vertex() {}
|
|
||||||
|
|
||||||
// Starts writing edge from vertex to vertex
|
|
||||||
void start_edge(Id from, Id to) {}
|
|
||||||
|
|
||||||
// Type of currently started edge
|
|
||||||
void edge_type(std::string const &et) {}
|
|
||||||
|
|
||||||
// Ends writing edge
|
|
||||||
void end_edge() {}
|
|
||||||
|
|
||||||
// Number of following paired property_name,handle calls.
|
|
||||||
void property_count(size_t n);
|
|
||||||
|
|
||||||
// Property family name of next property for currently started element.
|
|
||||||
void property_name(std::string const &name) {}
|
|
||||||
|
|
||||||
void handle(const Void &v) {}
|
|
||||||
|
|
||||||
void handle(const bool &prop) {}
|
|
||||||
|
|
||||||
void handle(const float &prop) {}
|
|
||||||
|
|
||||||
void handle(const double &prop) {}
|
|
||||||
|
|
||||||
void handle(const int32_t &prop) {}
|
|
||||||
|
|
||||||
void handle(const int64_t &prop) {}
|
|
||||||
|
|
||||||
void handle(const std::string &value) {}
|
|
||||||
|
|
||||||
void handle(const ArrayStore<bool> &) {}
|
|
||||||
|
|
||||||
void handle(const ArrayStore<int32_t> &) {}
|
|
||||||
|
|
||||||
void handle(const ArrayStore<int64_t> &) {}
|
|
||||||
|
|
||||||
void handle(const ArrayStore<float> &) {}
|
|
||||||
|
|
||||||
void handle(const ArrayStore<double> &) {}
|
|
||||||
|
|
||||||
void handle(const ArrayStore<std::string> &) {}
|
|
||||||
};
|
|
@ -1,107 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "database/db_accessor.hpp"
|
|
||||||
#include "storage/edge_accessor.hpp"
|
|
||||||
#include "storage/edge_type/edge_type.hpp"
|
|
||||||
#include "storage/label/label.hpp"
|
|
||||||
#include "storage/vertex_accessor.hpp"
|
|
||||||
|
|
||||||
namespace serialization {
|
|
||||||
|
|
||||||
// Serializes Vertex to given writer which implements GraphEncoder.
|
|
||||||
template <class W>
|
|
||||||
void serialize_vertex(VertexAccessor const &v, W &writer) {
|
|
||||||
// Serialize vertex id
|
|
||||||
writer.start_vertex(v.id());
|
|
||||||
|
|
||||||
// Serialize labels
|
|
||||||
auto const &labels = v.labels();
|
|
||||||
writer.label_count(labels.size());
|
|
||||||
for (auto &label : labels) {
|
|
||||||
writer.label(label.get().str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Serialize propertys
|
|
||||||
auto const &propertys = v.properties();
|
|
||||||
writer.property_count(propertys.size());
|
|
||||||
for (auto &prop : propertys) {
|
|
||||||
writer.property_name(prop.key.family_name());
|
|
||||||
prop.accept_primitive(writer);
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.end_vertex();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Serializes Edge to given writer which implements GraphEncoder.
|
|
||||||
template <class W>
|
|
||||||
void serialize_edge(EdgeAccessor const &e, W &writer) {
|
|
||||||
// Serialize to and from vertices ids.
|
|
||||||
writer.start_edge(e.from().id(), e.to().id());
|
|
||||||
|
|
||||||
// Serialize type
|
|
||||||
writer.edge_type(e.edge_type().str());
|
|
||||||
|
|
||||||
// Serialize propertys
|
|
||||||
auto const &propertys = e.properties();
|
|
||||||
writer.property_count(propertys.size());
|
|
||||||
for (auto &prop : propertys) {
|
|
||||||
writer.property_name(prop.key.family_name());
|
|
||||||
prop.accept_primitive(writer);
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.end_edge();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deserializes vertex from reader into database db. Returns Id which vertex had
|
|
||||||
// in the reader and VertexAccessor.
|
|
||||||
template <class D>
|
|
||||||
std::pair<Id, VertexAccessor> deserialize_vertex(DbAccessor &db, D &reader) {
|
|
||||||
auto v = db.vertex_insert();
|
|
||||||
auto old_id = reader.vertex_start();
|
|
||||||
|
|
||||||
// Deserialize labels
|
|
||||||
std::string s;
|
|
||||||
for (auto i = reader.label_count(); i > 0; i--) {
|
|
||||||
auto &label_key = db.label_find_or_create(reader.label().c_str());
|
|
||||||
v.add_label(label_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deserialize propertys
|
|
||||||
for (auto i = reader.property_count(); i > 0; i--) {
|
|
||||||
auto &family =
|
|
||||||
db.vertex_property_family_get(reader.property_name().c_str());
|
|
||||||
v.set(StoredProperty<TypeGroupVertex>(
|
|
||||||
family, reader.template property<Property>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
reader.vertex_end();
|
|
||||||
return std::make_pair(old_id, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deserializes edge from reader into database db. Returns loaded EdgeAccessor.
|
|
||||||
// S - is the storage with at() method for accesing VertexAccessor under thers
|
|
||||||
// deserialization local id returnd from deserialize_vertex.
|
|
||||||
template <class D, class S>
|
|
||||||
EdgeAccessor deserialize_edge(DbAccessor &db, D &reader, S &store) {
|
|
||||||
auto ids = reader.edge_start();
|
|
||||||
// Deserialize from and to ids of vertices.
|
|
||||||
VertexAccessor &from = store.at(ids.first);
|
|
||||||
VertexAccessor &to = store.at(ids.second);
|
|
||||||
|
|
||||||
auto e = db.edge_insert(from, to);
|
|
||||||
|
|
||||||
// Deserialize type
|
|
||||||
auto &edge_type_key = db.type_find_or_create(reader.edge_type().c_str());
|
|
||||||
e.edge_type(edge_type_key);
|
|
||||||
|
|
||||||
// Deserialize properties
|
|
||||||
for (auto i = reader.property_count(); i > 0; i--) {
|
|
||||||
auto &family = db.edge_property_family_get(reader.property_name().c_str());
|
|
||||||
e.set(StoredProperty<TypeGroupEdge>(family,
|
|
||||||
reader.template property<Property>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
reader.edge_end();
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,56 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2017 Memgraph
|
|
||||||
// Created by Florijan Stamenkovic on 01.02.17.
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <ostream>
|
|
||||||
#include "storage/property_value_store.hpp"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes all of the values from the given store in JSON format
|
|
||||||
* to the given output stream.
|
|
||||||
*
|
|
||||||
* @param store The store that should be serialized to JSON.
|
|
||||||
* @param ostream The stream to write to.
|
|
||||||
*/
|
|
||||||
void PropertyValuesToJson(const PropertyValueStore& store,
|
|
||||||
std::ostream& ostream = std::cout) {
|
|
||||||
bool first = true;
|
|
||||||
|
|
||||||
auto write_key =
|
|
||||||
[&ostream, &first](const PropertyValueStore::TKey& key) -> std::ostream& {
|
|
||||||
if (first) {
|
|
||||||
ostream << '{';
|
|
||||||
first = false;
|
|
||||||
} else
|
|
||||||
ostream << ',';
|
|
||||||
|
|
||||||
return ostream << '"' << key << "\":";
|
|
||||||
};
|
|
||||||
|
|
||||||
auto handler = [&ostream, &write_key](const PropertyValueStore::TKey& key,
|
|
||||||
const PropertyValue& value) {
|
|
||||||
switch (value.type_) {
|
|
||||||
case PropertyValue::Type::Null:
|
|
||||||
break;
|
|
||||||
case PropertyValue::Type::Bool:
|
|
||||||
write_key(key) << (value.Value<bool>() ? "true" : "false");
|
|
||||||
break;
|
|
||||||
case PropertyValue::Type::String:
|
|
||||||
write_key(key) << '"' << value.Value<std::string>() << '"';
|
|
||||||
break;
|
|
||||||
case PropertyValue::Type::Int:
|
|
||||||
write_key(key) << value.Value<int64_t>();
|
|
||||||
break;
|
|
||||||
case PropertyValue::Type::Float:
|
|
||||||
write_key(key) << value.Value<float>();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
auto finish = [&ostream]() { ostream << '}' << std::endl; };
|
|
||||||
|
|
||||||
store.Accept(handler, finish);
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "rapidjson/stringbuffer.h"
|
|
||||||
#include "rapidjson/writer.h"
|
|
||||||
#include "storage/model/properties/properties.hpp"
|
|
||||||
|
|
||||||
class RapidJsonStringWriter {
|
|
||||||
public:
|
|
||||||
// TODO: clear up naming
|
|
||||||
using sptr = std::shared_ptr<rapidjson::Writer<rapidjson::StringBuffer>>;
|
|
||||||
|
|
||||||
RapidJsonStringWriter(const sptr& writer) : writer(writer) {}
|
|
||||||
|
|
||||||
void handle(const std::string& key, Property& value, bool first) {
|
|
||||||
writer->String(key.c_str());
|
|
||||||
value.accept(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle(Bool& b) { writer->String(b.value() ? "true" : "false"); }
|
|
||||||
|
|
||||||
void handle(String& s) { writer->String(s.value.c_str()); }
|
|
||||||
|
|
||||||
void handle(Int32& int32) {
|
|
||||||
writer->String(std::to_string(int32.value).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle(Int64& int64) {
|
|
||||||
writer->String(std::to_string(int64.value).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle(Float& f) { writer->String(std::to_string(f.value).c_str()); }
|
|
||||||
|
|
||||||
void handle(Double& d) { writer->String(std::to_string(d.value).c_str()); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
sptr writer;
|
|
||||||
};
|
|
Loading…
Reference in New Issue
Block a user