Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Federated query validation error messages #621

Merged
merged 7 commits into from
Oct 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion deps.edn
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
byte-streams/byte-streams {:mvn/version "0.2.4"}
cheshire/cheshire {:mvn/version "5.12.0"}
instaparse/instaparse {:mvn/version "1.4.12"}
metosin/malli {:mvn/version "0.13.0"}
metosin/malli {:git/url "https://github.com/metosin/malli.git"
:git/sha "5211aca498ff7b022c36de4ca713990f5e731a9c" }
com.fluree/json-ld {:git/url "https://github.com/fluree/json-ld.git"
:git/sha "2b4a4cf75f2b823eea7fa221c6b9cbeb68299e90"}

Expand Down
146 changes: 0 additions & 146 deletions dev/errors.clj

This file was deleted.

4 changes: 2 additions & 2 deletions src/fluree/db/query/fql/syntax.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@
[:map-of ::json-ld-keyword :any]
[:fn
{:error/fn
(fn [{:keys [value]} _]
(str "Query: " (pr-str value) " does not have exactly one select clause. "
(fn [_ _]
(str "Query does not have exactly one select clause. "
cap10morgan marked this conversation as resolved.
Show resolved Hide resolved
"One of 'select', 'selectOne', 'select-one', 'selectDistinct', or 'select-distinct' is required in queries. "
"See documentation here for more details: "
docs/error-codes-page "#query-missing-select"))}
Expand Down
65 changes: 38 additions & 27 deletions src/fluree/db/validation.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
[malli.core :as m]
[malli.error :as me]
[malli.util :as mu]
[clojure.string :as str]))
[clojure.string :as str]
[clojure.walk :as walk]))

(defn iri?
[v]
Expand Down Expand Up @@ -55,8 +56,8 @@
(defn nearest-or-parent
"If a given error is the child of a disjunction,
returns the error data corresponding to that disjunction."
[error schema]
(let [{:keys [value path]} error]
[{:keys [schema value] :as _explained-error} error]
(let [{:keys [path in]} error]
(loop [i (dec (count path))]
(when-not (= 0 i)
(let [subpath (subvec path 0 i)
Expand All @@ -65,13 +66,14 @@
m/type)]
(if (#{:or :orn} type)
(let [props (m/properties schema-fragment)
in (mu/path->in schema subpath)]
in-length (count (mu/path->in schema subpath))
in' (subvec in 0 in-length)]
{:schema schema-fragment
:path subpath
:type type
:in in
:value value})
(recur (dec i) )))))))
:in in'
:value (get-in (walk/keywordize-keys value) in')})
(recur (dec i))))))))

(defn error-specificity-score
"Given an error, applies a heursitic
Expand Down Expand Up @@ -103,7 +105,7 @@
(portion of the value whch failed), and attempts to
find the nearest disjunction which contains all of
those errors. "
[{:keys [errors schema] :as _explained-error}]
[{:keys [errors] :as explained-error}]
(let [most-specific-errors (->> errors
(sort-by error-specificity-score)
(partition-by error-specificity-score)
Expand All @@ -112,14 +114,14 @@
(first most-specific-errors)
(let [same-in (val (first (group-by :in most-specific-errors)))
[e & es] same-in
or-parent (loop [{:keys [path] :as parent} (nearest-or-parent e schema)]
or-parent (loop [{:keys [path] :as parent} (nearest-or-parent explained-error e)]
(when parent
(if (every? (fn [err]
(let [path' (:path err)]
(when (<= (count path) (count path'))
(= path (subvec path' 0 (count path)))))) es)
parent
(recur (nearest-or-parent parent schema)))))]
(recur (nearest-or-parent explained-error parent)))))]
(or or-parent (first same-in))))))

(defn resolve-root-error-for-in
Expand Down Expand Up @@ -169,15 +171,16 @@
:orderBy
:commit-details
:t
:history})
:history
:from})

(defn format-error
[explained error error-opts]
(let [{:keys [path value]} error
top-level-key (some-> (first (filter top-level-query-keys path))
name)
(let [{full-value :value} explained
{:keys [path value]} error
top-level-key (first (filter top-level-query-keys path))
top-level-message (when top-level-key
(str "Error in value for \"" top-level-key "\""))
(str "Error in value for \"" (name top-level-key) "\""))
[_ root-message] (resolve-root-error-for-in
explained
error
Expand All @@ -189,11 +192,15 @@
docs-pointer-msg (when top-level-key
(str " See documentation for details: "
docs/error-codes-page "#query-invalid-"
(->> (str/replace top-level-key #"-" "")
(->> (str/replace (name top-level-key) #"-" "")
(map str/lower-case)
str/join)))]
str/join)))
provided-value (or value full-value)]
[top-level-message root-message direct-message
(str "Provided: " (pr-str value)) docs-pointer-msg]))
(some->> provided-value
pr-str
(str "Provided: "))
docs-pointer-msg]))

(defn top-level-fn-error
[errors]
Expand Down Expand Up @@ -239,7 +246,6 @@
[explained-error opts]
(let [error-opts (or opts default-error-overrides)
{:keys [errors schema value]} explained-error
[first-e] errors
e (or (top-level-fn-error errors)
(choose-relevant-error explained-error))]
(str/join "; " (remove nil? (distinct (format-error explained-error e error-opts))))))
Expand All @@ -250,13 +256,14 @@
(m/type-schemas)
(m/sequence-schemas)
(m/predicate-schemas)
{::iri [:or :string :keyword]
{::iri [:or {:error/message "invalid iri"}
:string :keyword]
::iri-key [:fn iri-key?]
::iri-map [:map-of {:max 1}
::iri-key ::iri]
::json-ld-keyword [:keyword {:decode/json decode-json-ld-keyword
:decode/fql decode-json-ld-keyword}]
::var [:fn {:error/message "Invalid variable, should be one or more characters begin with `?`"}
::var [:fn {:error/message "Invalid variable, should be one or more characters beginning with `?`"}
variable?]
::val [:fn value?]
::subject [:orn {:error/message "Subject must be a subject id, ident, or iri"}
Expand Down Expand Up @@ -291,16 +298,18 @@
:decode/json string->keyword
:error/message "Unrecognized operation in where map, must be one of: filter, optional, union, bind"}
:filter :optional :union :bind]
::graph [:orn
::graph [:orn {:error/message "Value of \"graph\" should be ledger alias or variable"}
[:ledger ::ledger]
[:variable ::var]]
::graph-map [:map {:closed true}
::graph-map [:map {:closed true
:error/message "Named where map must be a map specifying the graph to query and valid where clause"}
[:graph ::graph]
[:where [:ref ::where]]]
::where-map [:orn
::where-map [:orn {:error/message "Invalid where map, must be either named graph or valid where operation map"}
[:named ::graph-map]
[:default [:and
[:map-of {:max 1 :error/message "Unnamed where map can only have 1 key/value pair"} ::where-op :any]
[:map-of {:max 1 :error/message "Unnamed where map can only have 1 key/value pair"}
::where-op :any]
[:multi {:dispatch where-op}
[:filter [:map [:filter [:ref ::filter]]]]
[:optional [:map [:optional [:ref ::optional]]]]
Expand All @@ -314,9 +323,11 @@
[:where-map ::where-map]
[:tuple ::where-tuple]]]
::ledger ::iri
::from [:orn
::from [:orn {:error/message "from must be a ledger iri or vector of ledger iris"}
[:single ::ledger]
[:collection [:sequential ::ledger]]]
[:collection [:sequential
{:error/message "all values in `from`/`from-named` must be ledger iris"}
::ledger]]]
::from-named ::from
::delete [:orn {:error/message "delete statements must be a triple or vector of triples"}
[:single ::triple]
Expand Down