#7 It works, but it isn't actually useful
The problem is that bouncer doesn't seem really to support the idea that an object may satisfy one of a set of validations, and that's OK; and it doesn't seem to support collecting nested errors through custom validators. So although this will now tell you *that* an adl structure is invalid, it won't tell you *where* the document is invalid.
This commit is contained in:
		
							parent
							
								
									d5d26db037
								
							
						
					
					
						commit
						8e63f4b6c9
					
				|  | @ -115,7 +115,7 @@ | |||
|           {:tag :prompt | ||||
|            :attrs | ||||
|            {:prompt name | ||||
|             :local "en-GB"}}}}}}))) | ||||
|             :locale "en-GB"}}}}}}))) | ||||
| 
 | ||||
| 
 | ||||
| (defn make-entity-map [table-decl] | ||||
|  |  | |||
|  | @ -2,7 +2,6 @@ | |||
|       :author "Simon Brooke"} | ||||
|   squirrel-parse.validator | ||||
|   (:require [clojure.set :refer [union]] | ||||
|             [clojure.string :as s] | ||||
|             [bouncer.core :as b] | ||||
|             [bouncer.validators :as v])) | ||||
| 
 | ||||
|  | @ -30,7 +29,37 @@ | |||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| 
 | ||||
| ;;; this is a fairly straight translation of the ADL 1.4 DTD into Clojure | ||||
| (defn disjunct-validate | ||||
|   ;; OK, so: most of the validators will (usually) fail, and that's OK. How | ||||
|   ;; do we identify the one which ought not to have failed? | ||||
|   [o & validations] | ||||
|   (let | ||||
|     [rs (map | ||||
|          #(b/validate o %) | ||||
|          validations)] | ||||
|     ;; if *any* succeeded, we succeeded | ||||
|     ;; otherwise, one of these is the valid error - but which? The answer, in my case | ||||
|     ;; is that if there is any which did not fail on the :tag check, then that is the | ||||
|     ;; interesting one. But generally? | ||||
|     (empty? (remove :tag (map first rs))))) | ||||
| 
 | ||||
| (v/defvalidator disjunct-validator | ||||
|   ;; OK, so: most of the validators will (usually) fail, and that's OK. How | ||||
|   ;; do we identify the one which ought not to have failed? | ||||
|   {:optional false} | ||||
|   [value & validations] | ||||
|   (let | ||||
|     [rs (map | ||||
|          #(b/validate value %) | ||||
|          validations)] | ||||
|     ;; if *any* succeeded, we succeeded | ||||
|     ;; otherwise, one of these is the valid error - but which? The answer, in my case | ||||
|     ;; is that if there is any which did not fail on the :tag check, then that is the | ||||
|     ;; interesting one. But generally? | ||||
|     (empty? (remove :tag (map first rs))))) | ||||
| 
 | ||||
| ;;; the remainder of this file is a fairly straight translation of the ADL 1.4 DTD into Clojure | ||||
| 
 | ||||
| 
 | ||||
| (declare fieldgroup-validations) | ||||
| 
 | ||||
|  | @ -241,9 +270,9 @@ | |||
|   {:tag [v/required [#(= % :generator)]] | ||||
|    [:attrs :action] [v/string v/required [v/member generator-actions]] | ||||
|    [:attrs :class] v/string | ||||
|    :content [[v/every #(or | ||||
|                         (b/valid? % documentation-validations) | ||||
|                         (b/valid? % param-validations))]]}) | ||||
|    :content [[v/every #(disjunct-validate % | ||||
|                          documentation-validations | ||||
|                          param-validations)]]}) | ||||
| 
 | ||||
| 
 | ||||
| (def in-implementation-validations | ||||
|  | @ -354,23 +383,26 @@ | |||
|    [:attrs :distinct] [v/string [v/member #{"none", "all", "user", "system"}]] | ||||
|    [:attrs :entity] v/string | ||||
|    [:attrs :farkey] v/string | ||||
|    [:attrs :required] v/boolean | ||||
|    [:attrs :immutable] v/boolean | ||||
|    [:attrs :size] [[#(if | ||||
|    [:attrs :required] [[v/member #{"true", "false"}]] | ||||
|    [:attrs :immutable] [[v/member #{"true", "false"}]] | ||||
|    [:attrs :size] [[#(cond | ||||
|                       (empty? %) ;; it's allowed to be missing | ||||
|                       true | ||||
|                        (string? %) | ||||
|                        (integer? (read-string %)) | ||||
|                       true | ||||
|                        (integer? %))]] | ||||
|    [:attrs :column] v/string | ||||
|    [:attrs :concrete] v/boolean | ||||
|    [:attrs :concrete] [[v/member #{"true", "false"}]] | ||||
|    [:attrs :cascade] [[v/member cascade-actions]] | ||||
|    :content [[v/every #(or | ||||
|                         (b/valid? % documentation-validations) | ||||
|                         (b/valid? % generator-validations) | ||||
|                         (b/valid? % permission-validations) | ||||
|                         (b/valid? % option-validations) | ||||
|                         (b/valid? % prompt-validations) | ||||
|                         (b/valid? % help-validations) | ||||
|                         (b/valid? % ifmissing-validations))]]}) | ||||
|    :content [[v/every #(disjunct-validate % | ||||
|                          documentation-validations | ||||
|                          generator-validations | ||||
|                          permission-validations | ||||
|                          option-validations | ||||
|                          prompt-validations | ||||
|                          help-validations | ||||
|                          ifmissing-validations)]]}) | ||||
| 
 | ||||
| 
 | ||||
| (def permission-validations | ||||
|  | @ -418,7 +450,7 @@ | |||
|   * `dangerous`  true if this verb causes a destructive change." | ||||
|   {:tag [v/required [#(= % :verb)]] | ||||
|    [:attrs :verb] [v/string v/required] | ||||
|    [:attrs :dangerous] [v/boolean v/required]}) | ||||
|    [:attrs :dangerous] [[v/member #{"true", "false"}] v/required]}) | ||||
| 
 | ||||
| (def order-validations | ||||
|   "an ordering or records in a list | ||||
|  | @ -472,36 +504,35 @@ | |||
|   {:tag [v/required [#(= % :form)]] | ||||
|    [:attrs :name] [v/required v/string] | ||||
|    [:attrs :properties] [v/required [v/member #{"all", "user-distinct", "listed"}]] | ||||
|    [:attrs :canadd] v/boolean | ||||
|    :content [[v/every #(or | ||||
|                          (b/valid? % documentation-validations) | ||||
|                          (b/valid? % head-validations) | ||||
|                          (b/valid? % top-validations) | ||||
|                          (b/valid? % foot-validations) | ||||
|                          (b/valid? % field-validations) | ||||
|                          (b/valid? % fieldgroup-validations) | ||||
|                          (b/valid? % auxlist-validations) | ||||
|                          (b/valid? % verb-validations) | ||||
|                          (b/valid? % permission-validations) | ||||
|                          (b/valid? % pragma-validations))]]}) | ||||
|    [:attrs :canadd] [[v/member #{"true", "false"}]] | ||||
|    :content [[v/every #(disjunct-validate % | ||||
|                           documentation-validations | ||||
|                           head-validations | ||||
|                           top-validations | ||||
|                           foot-validations | ||||
|                           field-validations | ||||
|                           fieldgroup-validations | ||||
|                           auxlist-validations | ||||
|                           verb-validations | ||||
|                           permission-validations | ||||
|                           pragma-validations)]]}) | ||||
| 
 | ||||
| (def page-validations | ||||
|   "a page on which an entity may be displayed" | ||||
|   {:tag [v/required [#(= % :page)]] | ||||
|    [:attrs :name] [v/required v/string] | ||||
|    [:attrs :properties] [v/required [v/member #{"all", "user-distinct", "listed"}]] | ||||
|    :content [[v/every #(or | ||||
|                          (b/valid? % documentation-validations) | ||||
|                          (b/valid? % head-validations) | ||||
|                          (b/valid? % top-validations) | ||||
|                          (b/valid? % foot-validations) | ||||
|                          (b/valid? % field-validations) | ||||
|                          (b/valid? % fieldgroup-validations) | ||||
|                          (b/valid? % auxlist-validations) | ||||
|                          (b/valid? % verb-validations) | ||||
|                          (b/valid? % permission-validations) | ||||
|                          (b/valid? % pragma-validations) | ||||
|                          )]]}) | ||||
|    :content [[v/every #(disjunct-validate % | ||||
|                           documentation-validations | ||||
|                           head-validations | ||||
|                           top-validations | ||||
|                           foot-validations | ||||
|                           field-validations | ||||
|                           fieldgroup-validations | ||||
|                           auxlist-validations | ||||
|                           verb-validations | ||||
|                           permission-validations | ||||
|                           pragma-validations)]]}) | ||||
| 
 | ||||
| (def list-validations | ||||
|   "a list on which entities of a given type are listed | ||||
|  | @ -512,19 +543,18 @@ | |||
|    [:attrs :name] [v/required v/string] | ||||
|    [:attrs :properties] [v/required [v/member #{"all", "user-distinct", "listed"}]] | ||||
|    [:attrs :onselect] v/string | ||||
|    :content [[v/every #(or | ||||
|                          (b/valid? % documentation-validations) | ||||
|                          (b/valid? % head-validations) | ||||
|                          (b/valid? % top-validations) | ||||
|                          (b/valid? % foot-validations) | ||||
|                          (b/valid? % field-validations) | ||||
|                          (b/valid? % fieldgroup-validations) | ||||
|                          (b/valid? % auxlist-validations) | ||||
|                          (b/valid? % verb-validations) | ||||
|                          (b/valid? % permission-validations) | ||||
|                          (b/valid? % pragma-validations) | ||||
|                          (b/valid? % order-validations) | ||||
|                          )]]}) | ||||
|    :content [[v/every #(disjunct-validate % | ||||
|                           documentation-validations | ||||
|                           head-validations | ||||
|                           top-validations | ||||
|                           foot-validations | ||||
|                           field-validations | ||||
|                           fieldgroup-validations | ||||
|                           auxlist-validations | ||||
|                           verb-validations | ||||
|                           permission-validations | ||||
|                           pragma-validations | ||||
|                           order-validations)]]}) | ||||
| 
 | ||||
| (def key-validations | ||||
|   {:tag [v/required [#(= % :key)]] | ||||
|  | @ -550,18 +580,17 @@ | |||
|    [:attrs :name] [v/required v/string] | ||||
|    [:attrs :natural-key] v/string | ||||
|    [:attrs :table] v/string | ||||
|    [:attrs :foreign] v/boolean | ||||
|    :content [[v/every #(or | ||||
|                         (b/valid? % documentation-validations) | ||||
|                         (b/valid? % prompt-validations) | ||||
|                         (b/valid? % content-validations) | ||||
|                         (b/valid? % key-validations) | ||||
|                         (b/valid? % property-validations) | ||||
|                         (b/valid? % permission-validations) | ||||
|                         (b/valid? % form-validations) | ||||
|                         (b/valid? % page-validations) | ||||
|                         (b/valid? % list-validations) | ||||
|                         )]]}) | ||||
|    [:attrs :foreign] [[v/member #{"true", "false"}]] | ||||
|    :content [[v/every #(disjunct-validate % | ||||
|                          documentation-validations | ||||
|                          prompt-validations | ||||
|                          content-validations | ||||
|                          key-validations | ||||
|                          property-validations | ||||
|                          permission-validations | ||||
|                          form-validations | ||||
|                          page-validations | ||||
|                          list-validations)]]}) | ||||
| 
 | ||||
| (def application-validations | ||||
|   {:tag [v/required [#(= % :application)]] | ||||
|  | @ -569,15 +598,62 @@ | |||
|    [:attrs :version] v/string | ||||
|    [:attrs :revision] v/string | ||||
|    [:attrs :currency] v/string | ||||
|    :content [[v/every #(or | ||||
|                         (b/valid? % specification-validations) | ||||
|                         (b/valid? % documentation-validations) | ||||
|                         (b/valid? % content-validations) | ||||
|                         (b/valid? % typedef-validations) | ||||
|                         (b/valid? % group-validations) | ||||
|                         (b/valid? % entity-validations))]]}) | ||||
|    :content [[v/every #(disjunct-validate % | ||||
|                          specification-validations | ||||
|                          documentation-validations | ||||
|                          content-validations | ||||
|                          typedef-validations | ||||
|                          group-validations | ||||
|                          entity-validations)]]}) | ||||
| 
 | ||||
| ;; the good news: it's complete. | ||||
| ;; the bad news: it doesn't yet work. | ||||
| ;; TODO: write a function which takes the output of bouncer.core.validate and filters out the paths to those bits which failed. | ||||
| 
 | ||||
| (defn find-keys | ||||
|   [o p] | ||||
|   (cond | ||||
|    (map? o) | ||||
|    (reduce | ||||
|     merge | ||||
|     {} | ||||
|     (map | ||||
|      (fn [k] | ||||
|        (let [tail (find-keys (o k) p)] ;; error is here | ||||
|         (cond | ||||
|          (not (empty? tail)) | ||||
|          {k tail} | ||||
|          (p k) | ||||
|          {k (o k)} | ||||
|          true | ||||
|          {}))) | ||||
|      (keys o))) | ||||
|    (coll? o) | ||||
|    (remove empty? (map #(find-keys % p) o)))) | ||||
| 
 | ||||
| (defn walk-find-keys | ||||
|   [o p] | ||||
|   (walk | ||||
|    #(do %) | ||||
|    #(cond | ||||
|      (map? %) | ||||
|      (reduce | ||||
|       {} | ||||
|       (remove | ||||
|         empty? | ||||
|        (map | ||||
|         (fn [k] | ||||
|           (cond | ||||
|            (p k) | ||||
|            {k (% k)} | ||||
|            (walk-find-keys (% k) p) | ||||
|            {k (walk-find-keys (% k) p)})) | ||||
|         (keys %)))) | ||||
|      (coll? %) | ||||
|      (remove | ||||
|       empty? | ||||
|       (map | ||||
|        (fn [e] | ||||
|          (walk-find-keys e p)) | ||||
|        %))) | ||||
|    o)) | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue