This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2015-11-03
Channels
- # admin-announcements (7)
- # beginners (30)
- # boot (181)
- # cbus (1)
- # cider (55)
- # cljs-dev (8)
- # clojure (104)
- # clojure-dev (3)
- # clojure-japan (1)
- # clojure-russia (70)
- # clojurescript (139)
- # core-logic (4)
- # cursive (23)
- # datomic (25)
- # devcards (10)
- # events (11)
- # funcool (1)
- # hoplon (39)
- # jobs (10)
- # ldnclj (19)
- # lein-figwheel (21)
- # off-topic (4)
- # om (174)
- # onyx (46)
- # re-frame (25)
- # reagent (3)
- # yada (7)
Как же все-таки Ruby с Rails (в особенности) расслабляет да? Ни о чем думать не надо - клепай из компонентиков уже написанных гемов проекты и живи спокойно. Не подумайте ничего плохого - сам с 2009 года на Rails (и до сих пор)… просто привыкли к тому что фреймворк все сам за нас делает, вот и непривычно ручками все делать 😉
думаю, что на honeysql тоже можно напилить похожих абстракций, просто ни у кого руки не дошли все правильно обобщить
проблема рельс не в том, что там уже все есть (было бы странно), а в том, что когда приходится сражаться с фреймворком, начинается боль и ужас
@kirillov: да клепаешь пока не надо внутрь тут либо вначале думаешь, либо потом "не знаешь что и думать". Реализовать большую часть магии ORM на clojure не очень сложно, если понимаешь как она работает
Проект простой: «оперировать запросами напрямую, фу». Прошло два года: «ух ты, всё нужное вытаскивается одним эпичным запросом». Может, и не в проекте дело.
@kirillov: поддерживаю абсолютно, с недавнего времени начал понимать, как много вещей в рельсе мы принимаем как должное, сам хотел дать такой ответ, но это же грустно. вот приходит новичок а @nicola ему "можешь для этого парочку generic хэлперов” 😕 нужны примеры и наверное даже лучше - скаффолды таких хелперов (ну уж не нам ли с макросами и "code is data" генераторы кода то писать?)
@nicola > Умное обновление пиши ручками в сервисной функции, можешь для этого парочку generic хэлперов написать (update-association task :subtasks) Такая функция будет выглядеть вот так?
(defn save [task]
;; make updates in database
)
или вот так:
(defn save [id new-title new-subtasks updated-subtasks deleted-subtasks]
;; make updates in database
)
Для реализации первого варианта, чтобы обновить в базе только действительно обновленные поля придется написать свою орм.
Ведь нам нужно знать какой объект был до его "обновления", чтобы обновить только то, что нужно.
Если же использовать второй вариант, то работа с этой функцией будет выглядит довольно таки сложно в случае обновления агрегата.
Кто как поступает? Есть ли best practice как абстрагироваться от бд в фп?я не понял проблему. Ты что хочешь сделать? Обновить сабтаск? Обновляй сабтаск, чего ты к таске пристал?
тут проблема в том, что у меня сабтаск это часть агрегата task(в терминал domain driven design), то есть сабтаск это часть объекта task. Соответственно обновлять таск и сабтаски должна одна функция.
Возьмем пример попроще. Есть объект task: { id: 123, title: "Buy a milk" }, бизнес правило: title не может быть пустым. Есть функция update-task которая принимает данные от пользователя:
(ns 'app.api)
(defn update-task [id title]
(let [
task find-task-by-id(id)
updated-task update-title(task title)
]
(save task) ;; or (save id (:title updated-task))
)
(defn update-title [task title]
(check-not-empty title)
(assoc task :title title)
)
так вот вопрос, правильно ли я написал код с точки зрения фп(достал из базы таск, "обновил" его, сохранил изменения в базу)?
И второй вопрос, какой вариант функции save вы бы выбрали: (save task) или (save id title)?по-моему, ты с точки зрения sql все неправильно сделал.
update
from tasks
where task_id = 42
set title = :title
если нечего обновлять, запрос подействует на 0 строк и можно падать или как ты там хотел обрабатывать эту ситуацию
@deeper4k: update-task легко параметризуется именем таблицы и валидатором в общую функцию update
надо стараться разбить свою логику на чистую и грязную, стараясь побольше работы перенести в чистые функции.
@nicola: > update-task легко параметризуется именем таблицы и валидатором в общую функцию update а если у меня обновление таска это не только валидация и сохранение, но и вызовы например каких-то других сервисов?
> в смысле, зачем тебе сначала находить? потому что мне возможно понадобятся другие атрибуты таска, например для валидации
@nicola: я ведь правильно понимаю, что лучше параметризовать мою чистую функцию функцией save, которая сделает грязную работу(сохранит изменения в базу)?
Если ты хочешь абстрагироваться от базы можно и подобный Dependency Injection сделать - но много писать придеться
Пишешь generic набор грязных функций для работы с базой - порождения sql : update, create, delete, select etc
Всякие вещи похитрее как обновление ассоциаций, жадная загрузка тоже пишешь в общем виде
спасибо, я как раз пытался выяснить есть ли готовое решение для абстракции, выходит что нет
базовый ORM (ala ActiveRecord || Hibernate) впринципе не сложно повторить - но будет выглядить не clojure way
у нас в парочке проектов ушло вначале по недельке на написание подточенного под проблемы ala-ORM и потом постепенное эвалюционированние в разных направлениях
например метаданные о сущностях можно в стиле ActiveRecord доставать из метаданных базы или получать из swagger
вобщем как раз появляеться композабельность и тонкая подгонка под проблемы решаемые приложением
в одном проекте мы например расширили honeysql, чтобы он делал жадную загрузку: {:select [:*] , :from [:user], :with [:groups :settings]} - там на пол странички кода
да с границей не всегда понятно, но без агрегатов у нас в приложении местами было бы сложно. Это там где агрегат гарантирует консистентность своих детей
я больше склоняюсь к use-case driven - те вычленять не структурную модель, а поведеньческую
@nicola: может соберешь гисты ассоциаций, форм билдера и что есть в репо типа howto/cookbook?
@deeper4k: раз уж тут заговорили про всякие ассоциации с sql то автор honeysql как-то пытался пилить https://github.com/jkk/cantata. не в плане “стоит использовать”, но”посмотреть"