Как стать автором
Обновить
33
13
Евгений @fnc12

Разработчик

Отправить сообщение

ахаха, лучший коммент)

согласен полностью с тем, что обучение гита лучше начинать с консоли. Фишка консоли именно в том, что там ты должен использовать оригинальные команды гита как они есть, а не кнопки, которые не всегда делают очевидные вещи. Идея колеса с командами в данной статье как раз пришла именно оттуда — суть колеса в том, что оно отображает команды один в один без искажений.

Полностью согласен с автором. Я когда начал писать свою ORM-либу на плюсах мне то же самое говорили https://github.com/fnc12/sqlite_orm. А сейчас она на втором месте по кол-ву звезд среди ORM для SQLite3 на плюсах на гитхабе

уже есть все джоины

я так понял ваш вопрос состоит в том, чтобы как-то вывести тип хранилища. Это очень популярный вопрос у пользователей sqlite_orm, и ответ на него я подробно описал в FAQ на github вот тут https://github.com/fnc12/sqlite_orm/wiki/FAQ

Прекраснейшая новость. Вот только лишь бы не реализовали новую версию винампа на электроне

добавлять методы к классу можно если методы шаблонные путем специализаций. Это не идеал, но очень похоже

#include <codecvt> — там все есть

проверьте в нынешней версии — теперь есть и GROUP BY, и JOIN (все виды кроме NATURAL и SELF)

Посмотрев внимательнее ODB я нашел еще одну важную вещь, которая есть в sqlite_orm и отсутствует в ODB — это возможность именовать столбцы таблиц независимо от имен полей класса. Как бы это смешно не звучало, но если в схеме есть колонка "new", например, то в C++ такой код не скомпилируется. Самое забавное, что если сменить язык на тот, в котором слово "new" не зарезервировано, то все заработает. Я сталкивался с таким лично в разработке (правда, это был enum-маппер, либа https://github.com/aantron/better-enums). Уговорить бэкенд разраба чтобы он поменял имя колонки в таблице только потому что это слово зарезервировано языком, на котором написан один из клиентов, нереально, да и идиоматически это неверно, на моя взгляд.

@igorjan94 я понял, теперь я нахожусь в процессе осознания, что вложенные сущности нужны. Но вот такой вопрос от меня: в случае если есть такая схема (буду писать коротко):
books ( id:int, name:string, category_id:int )
categories ( id:int, name:string )
то подразумевается, что получая книгу, в ней есть вложенная категория с указанным id. То есть, ORM за юзера выполняет каскадный SELECT и достает нужную категорию. Это я понял. Но вот вопрос: а что если ссылки взаимные, то есть у категории есть id книги, которую добавили самой последней в эту категорию, например. Так:
categories ( id:int, name:string, last_added_book_id:int? )
Тут может быть такая ситуация, когда книга ссылается на категорию, которая ссылается на эту же книгу, которая ссылается на эту же категорию. В данном случае что делает ORM (например, та сама на js, которую, кажется, вы мне рекомендовали как пример)? Попадает в бесконечную рекурсию?

окей, тогда мне следует добавить поддержку этого в sqlite_orm. И если один ко многих ясно как сделать, то вектор устроен хитрее — тут надо умно и очевидно указывать какая таблица выполняет роль словаря (в нашем случае это books_categories)

Тут другой случай — тут не просто абы-какие поля, о которых хранилище не знает, тут поля, типы которых связаны с хранилищем, но не в том виде, в котором они оформлены внутри структур. Это порождает несоответствие схемы в бд схеме доменной модели в программе и делает код менее читабельным, и, как следствие, менее поддерживаемым. А если у меня просто будет лишнее поле, которое не нужно сериализоваться (хэш имени пользователя, например), то это не породит неясностей, так как ясно, что это приблуда

Добавить поля, которые не сериализуются, в структуру не составляет проблем. Это даже подразумевается либой. Просто не создавайте колонку при создании хранилища со ссылкой на это поле и все

Пожалуйста. Впервые с IOD я столкнулся вот тут http://siliconframework.org. Может этот фреймворк будет вам тоже интересен.


Насчет ODB — классная штука за одним исключением — предкомпилятором. С++ и без того получает много критики за наличие сишного препроцессора. А если я подключу либу с предпредкомпилятором, что тогда получится? А если у меня две? Три? Кто первичен? Кто вторичен? Почему именно так? Например, у меня проект на Qt (у него есть MOC), я подключил ODB (у него своя приблуда), и еще IOD добавил, у него свой скрипт, который генерит заголовок с символами. Это все порождает путаницу и выходит за пределы возможностей] языка. Именно поэтому я такую черную магию не одобряю. Это мое личное мнение. Не сомневаюсь, что те два ваших проекта, которые содержали ODB, отлично функционировали в области взаимодействия с БД.

Все правильно, они и не должны.

Что?
sqlite_orm как и любая другая sqlite ORM библиотека отправляет запросы в первую очередь в SQLite. И разработчик работая с ORM или еще каким-угодно фронтэндом БД должен понимать в какие запросы его клиентский код вырождается в результате. Так вот: когда классы соответствуют схеме — это делает код очень читабельным в плане "где и какой sql запрос отправляется". Иначе повышается шанс быдлокодинга, так как новичок может не понимать какие запросы под собой подразумевает вот эта простая и удобная в использовании функция. Именно поэтому последний пример


auto categories = storage.get_all<Category>(where(in(&Category::id,
   storage.select(&BookCategory::categoryId, where(is_equal(&BookCategory::bookId, book.id)))
)));

идеально иллюстрирует вложенный запрос:


SELECT * FROM categories WHERE id IN (
   SELECT category_id FROM books_categories WHERE book_id = ?
)

Второе: поддержки std::experimental::optional<T> в sqlite_orm нет пока он не выйдет из experimental namespace (ожидается в С++17). Опциональные значения используют std::shared_ptr<T> либо std::unique_ptr<T>. Это неудобно, согласен. Я думал добавить сырые С-указатели, но этого не будет — вместо этого я добавлю трэйты чтобы можно было подключать свои типы полей — собственные строки, собственные опционалы. Там уже разработчик если хочет — добавит С-указатели или Glib::ustring, QString etc.


А вообще у меня мысли такие: сделать возможность хранить вложенную сущность (пока только в одном экземпляре) в виде поля типа std::shared_ptr<T> где T это другой класс также связанный с хранилищем. Насчет векторов тут надо подумать. Ваш совет про make_many_to_many_association очень интересен

По правде сказать из всех ORM-библиотек, которые я видел, ODB меня впечатлила больше всего. У меня вопрос: кто именно занимается парсингом прагм? Тут, похоже, есть кастомный предкомпилятор как у Qt (MOC) или у IOD (https://github.com/matt-42/iod) парсер символов

Идея отличная, только структуры схеме не соответствуют. Это создает неочевидности. Я не говорю, что вы что-то говорите неверно, я пытаюсь понять как лучше добавить возможность вложенных сущностей.


Вообще при схеме (добавил NOT NULL так как зануляемые значения мапятся в указатели только)


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

Достать все категории конкретной книги можно так:


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

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

struct BookCategory {
   int categoryId;
   int bookId;
};

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_table("categories",
                                       make_column("id", &Category::id, primary_key()),
                                       make_column("name", &Category::name)),
                            make_table("books_categories",
                                       make_column("category_id", &BookCategory::categoryId),
                                       make_column("book_id", &BookCategory::bookId)));

auto book = storage.get<Book>(2);
auto categories = storage.get_all<Category>(where(in(&Category::id,
   storage.select(&BookCategory::categoryId, where(is_equal(&BookCategory::bookId, book.id)))
)));

Вот так это делается


auto user = storage.get<User>(123);
auto userType = storage.get<UserType>(user.typeId);

Точнее "таблично-ориентированность" называется отсутствием вложенных сущностей.


По правде сказать вы уже не первый кто говорит про это, и я задумался как можно вложенность реализовать в sqlite_orm

Информация

В рейтинге
417-й
Откуда
Алматы (Алма-Ата), Алма-Атинская обл., Казахстан
Дата рождения
Зарегистрирован
Активность