Skip to content

Instantly share code, notes, and snippets.

@darkleaf
Last active January 2, 2019 14:27
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save darkleaf/f2e076c8810e8d4e131c55c0679d3984 to your computer and use it in GitHub Desktop.
Save darkleaf/f2e076c8810e8d4e131c55c0679d3984 to your computer and use it in GitHub Desktop.

Идея - валидировать данные, задавая путь к значению и проверющий предикат.

Проблема в том, что не понятно какой формат должен иметь отчет об ошибках. Допустим, ошиибка в множестве, или в ключе мапы. Как указать путь к ошибочному значению? Что потом с этим путем делать?

#{ {:key :correct}  {:key :wrong} }

{ {:key :wrong} :value }

Как вариант можно ссылылаться на сами объекты. Но строки, числа, кейворды и т.п. переиспользуются, т.е. 2 сроки с одинаковым содержимым - всегда один и тот же объект. Плюс, один и тот же объект может появляться не сколько раз в разных местах структуры.

Пока я заменяю все объекты не коллекции на обертку. И возвращаю измененную структуру и плоскую мапу с ошибками.

(ns validate
(:require
[com.rpl.specter :as sp]))
(declare ^:dynamic *errors*)
(deftype ScalarWrapper [value])
(defn value [x]
(if (instance? ScalarWrapper x)
(.-value x)
x))
(defn errors [x]
(if (.containsKey *errors* x)
(.get *errors* x)
(list)))
(defn add-error [x error]
(let [obj (if (or (instance? java.util.Collection x)
(instance? java.util.Map x)
(instance? ScalarWrapper x))
x
(ScalarWrapper. x))
obj-errors (errors obj)
obj-errors (conj obj-errors error)]
(.put *errors* obj obj-errors)
obj))
(defn check [path predicate]
(-> (if (vector? path) path [path])
(conj (sp/pred #(-> % value predicate not)))
(conj (sp/terminal #(add-error % :error))))) ;; что-то осмысленное вместо :error
(let [data {:publication/id 1
:publication/translations {:de {:publication.translation/title nil
:publication.translation/published-at nil
:article.translation/content "foo"}
:ru {:publication.translation/title "article ru"
:pbulication.translation/published-at nil
:article.translation/content "foo ru"}}
:article/image-url "http://"}
path (sp/multi-path (check [:publication/translations]
#(= 3 (count %)))
(check [:publication/translations
sp/MAP-VALS
:publication.translation/title]
string?))]
(binding [*errors* (java.util.IdentityHashMap.)]
[(sp/multi-transform path data)
*errors*]))
;; результат:
(comment
[
;; data, невалидные скалярные значения обернуты в ScalarWrapper
;; :de :title
{:publication/id 1,
:publication/translations {:de {:publication.translation/title #object[validate.ScalarWrapper 0x2fc7ae79 "validate.ScalarWrapper@2fc7ae79"],
:publication.translation/published-at nil,
:article.translation/content "foo"},
:ru {:publication.translation/title "article ru",
:pbulication.translation/published-at nil,
:article.translation/content "foo ru"}},
:article/image-url "http://"}
;; мапа с ошибками
;; ключ - ссылка на объект
;; значение - список ошибок
{
{:de {:publication.translation/title nil, :publication.translation/published-at nil, :article.translation/content "foo"}, :ru {:publication.translation/title "article ru", :pbulication.translation/published-at nil, :article.translation/content "foo ru"}}
(:error),
#object[validate.ScalarWrapper 0x2fc7ae79 "validate.ScalarWrapper@2fc7ae79"]
(:error)
}])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment