Pull to refresh
34
0
Евгений @fnc12

Разработчик

Send message

я не спорю, что pragma это очень важный и нужный инструмент. То же самое можно сказать даже про макросы. Однако речь не об этом, а о том, что при подключении ORM приходится модифицировать код модели. Вот тут https://habrahabr.ru/post/263027/ очень хорошо описано почему так делать не надо

Очень интересный кейс. Чтобы его воспроизвести в sqlite_orm нужно время. А пока в последнем коммите добавлена возможность выбора нескольких колонок как вы и говорили. В конце статьи добавлен пример

Понял, в каком финальном виде вы хотите получить данные?

нет, не понял ни первое, ни второе. 1) почему прослойка не нужна при использовании статичных С-массивов? 2) "С++ располагает к использованию UserType typeId; вместо int userTypeId; т.е. к использованию иерархического дерева объектов вместо таблиц." — вы про вложенные сущности? Если да, то вложенные сущности это ад. Это понимаешь, когда пытаешься масштабировать систему. Вложенные сущности актуальны в проектах с небольшим сроком жизни. Я не спорю — таких очень много, поэтому на вложенные сущности много кто смотрит как на нечто удобное. Плюс в таком виде как вы показали вложенные сущности не скомпилируются если вложение взаимное. Если я вас понял неверно — поясните пожалуйста.

расскажите поподробнее. Изначально цель sqlite_orm покрыть бОльшую часть использования sqlite3 в приложениях, а значит ваш кейс особенно интересен. Покажите схему как хотите хранить отношения многие ко многим. Отдельным словарем или как?

пунктом про single responsibility

В вашем примере есть вложенные сущности, а они не поддерживаются в sqlite_orm просто потому что это усложняет основу системы. Более того, взаимновложенные сущности не скомпилируются в С++ вообще (при условии агрегации).


А то, о чем вы говорите, реализуется в sqlite_orm вот так:


struct Book {
    int id;
    std::string name;
    int categoryId;
    int createdAt;
};

struct Category {
    int id;
    std::string name;
};

using namespace sqlite_orm;
auto storage = make_storage("db.sqlite",
                            make_table("books",
                                       make_column("id", &Book::id, primary_key()),
                                       make_column("name", &Book::name),
                                       make_column("category_id", &Book::categoryId),
                                       make_column("created_at", &Book::createdAt)),
                            make_table("categories",
                                       make_column("id", &Category::id, primary_key()),
                                       make_column("name", &Category::name)));

//  лимита нет, каюсь, в ближайших коммитах будет
auto books = storage.get_all<Book>(order_by(&Book::createdAt));
// теперь вытащим вектор из id категорий
std::vector<decltype(Book::categoryId)> categoryIds;
categoryIds.reserve(books.size());
std::transform(books.begin(); 
               books.end();
               std::back_inserter(categoryIds),
               [](auto &book) {
                   return book.categoryId;
               });
// std::transform может быть неудобен, но это православная stl-реализация функции map

auto categories = storage.get_all<Category>(where(in(&Category::id, categoryIds)));
// теперь books содержит выбранные книги, а categories - их категории

Или можно сымитировать сложные запрос:


auto books = storage.get_all<Book>(order_by(&Book::createdAt));
auto categories = storage.get_all<Category>(where(in(&Category::id, 
    storage.select(&Book::categoryId)
)));

Расскажите, пожалуйста, поподробнее про "возможность достать связанные foreign keyем сущности". Я так понимаю это что-то типа взяли юзера, у него есть поле category_id, достали категорию с этим id?

разумное замечание. Сейчас я размышляю сделать так: оставить get_all, добавить auto it = storage.iterate<User>().begin();. Итератор будет хранить в себе statement указатель, оператор* будет возвращать объект, оператор++ будет двигать statement вперед, storage.iterate<T>.end() будет возвращать итератор с нулевым statement. При присвоении итератору .end() или при очередном оператор++ когда достигнут конец таблицы итератор закрывает statement. В общем, получится forward iterator полностью stl-совместимый. Тут, конечно, есть косяк, что итератор хранит важную инфу, что не совсем stl-style, но с другой стороны можно будет делать так:


for(auto &user : storage.iterate<User>()) {
  if(user.id == idBeingSearch) break;
}

И после break statement закроется, что по сути и есть то, о чем вы говорите — одномоментно в памяти висит только один юзер, а не все сразу.

CREATE TABLE books(id INTEGER PRIMARY KEY, name TEXT);
CREATE TABLE categories(id INTEGER, name TEXT)
CREATE TABLE books_categories(category_id INTEGER, book_id INTEGER)


Вы подразумеваете такую схему? И напишите пожалуйста запрос каким бы вы достали данные для пунктов 1 и 2. Спасибо

select присутствует для одной колонки только пока. В ближайших коммитах будет интерфейс для выбора нескольких колонок в std::tuple: auto vectorOfTuples = storage.select(columns(&User::id, &User::firstName));.
Насчет JOIN и GROUP BY покажите примеры из своей практики чтобы я понял вас лучше. Спасибо

в нынешней версии библиотеки связей нет. Вообще уже был запрос один добавить foreign key. В целом это сделать несложно, вопрос в другом — нужно ли это во встраиваемой БД. Лично я не использую связи даже при их логическом наличии, так как это создает runtime overhead. Однако спасибо за отзыв — в дальнейших версиях обязательно будет добавлена функция foreing_key со ссылкой на поле другого класса.

Information

Rating
Does not participate
Location
Алматы (Алма-Ата), Алма-Атинская обл., Казахстан
Date of birth
Registered
Activity