From 322e8b2cafe4f8dfc8dfbdae9ed6fd1b0ec1b429 Mon Sep 17 00:00:00 2001 From: mj83 Date: Wed, 5 Oct 2016 00:36:45 +0200 Subject: [PATCH] add specter, refactoring started --- project.clj | 3 +- src/lovii_schema/schema.clj | 80 ++++++++++++++++++++- test/lovii_schema/schema_test.clj | 111 ++++++++++++++++++++++++++++++ 3 files changed, 190 insertions(+), 4 deletions(-) create mode 100644 test/lovii_schema/schema_test.clj diff --git a/project.clj b/project.clj index a494dd8..83ea5cf 100644 --- a/project.clj +++ b/project.clj @@ -6,7 +6,8 @@ :profiles {:dev {:dependencies [[org.clojure/clojure "1.8.0"] [cheshire "5.5.0"] [prismatic/schema "1.0.5"] - [com.datomic/datomic-free "0.9.5201" :exclusions [joda-time]]] + [com.datomic/datomic-free "0.9.5201" :exclusions [joda-time]] + [com.rpl/specter "0.13.0"]] :plugins [[com.jakemccrary/lein-test-refresh "0.10.0"]] :main lovii-schema.core}} :plugins [[lein-cljfmt "0.5.1"]] diff --git a/src/lovii_schema/schema.clj b/src/lovii_schema/schema.clj index 7f75dc8..379889a 100644 --- a/src/lovii_schema/schema.clj +++ b/src/lovii_schema/schema.clj @@ -1,4 +1,6 @@ -(ns lovii-schema.schema) +(ns lovii-schema.schema + (:require [com.rpl.specter :as sp]) + (:use [com.rpl.specter.macros])) (defn- add-namespace [k n] @@ -79,9 +81,55 @@ (apply-fns [cardinality-one]) (apply-fns fns))))) -(defn- expand-schema-variant +(defn expand-schema-variant2 [sch] + (let [; able to transform + ;{:users {:schema/variant :users}} into + ;{:users {:schema/variant {:variant :users}}} + vm [sp/MAP-VALS (sp/must :schema/variant) keyword?] + ; able to transform + ;{:users [{:schema/variant :users}}] into + ;{:users [{:schema/variant {:variant :users}}]} + vv [sp/MAP-VALS sp/ALL (sp/must :schema/variant) keyword?] + + fix (fn [v] {:variant v})] + (->> sch + (sp/transform vm fix) + (sp/transform vv fix)))) + +(defn expand-schema-abstract2 [sch] + (let [; able to transform + ;{:users {:schema/abstract :users}} into + ;{:users {:schema/abstract {:abstract :users}}} + vm [sp/MAP-VALS (sp/must :schema/abstract) keyword?] + + ; able to transform + ;{:users [{:schema/abstract :users}}] into + ;{:users [{:schema/abstract {:abstract :users}}]} + vv [sp/MAP-VALS sp/ALL (sp/must :schema/abstract) keyword?] + + fix (fn [v] {:abstract v})] + (->> sch + (sp/transform vm fix) + (sp/transform vv fix)))) + +(comment + (sp/select [sp/MAP-VALS] {:a 1 :b 2} ) + (sp/select [sp/ALL] {:a 1 :b 2} ) + (sp/select [sp/VAL] {:a 1 :b 2 :c {:d 5} } ) + (sp/select [sp/MAP-VALS keyword?] {:a :FF :b 2} ) + (sp/select [:c] {:a 1 :b 2} ) + (sp/transform [sp/MAP-VALS] (fn [m] :vv) {:a 5 :b 2}) + (sp/transform [sp/MAP-VALS map? (sp/must :e) ] (fn [m] :vv) {:a 5 :b 2 :c {:d 5} }) + (sp/transform (sp/select [sp/MAP-VALS {:a 5 :b 2} ]) inc {:a 5 :b 2}) + (sp/transform (sp/select [sp/ALL sp/LAST] {:a 5 :b 2} ) inc {:a 5 :b 2}) + (sp/transform (sp/select [sp/VAL] {:a 5 :b 2} ) (fn [m] {:c 9}) {:a 5 :b 2}) + (sp/transform [sp/ALL :a] dec [{:a 2 :b 3} {:a 1} {:a 4}]) + ) + + +(defn expand-schema-variant [m] - (let [variant (-> m :schema/variant) + (let [variant (-> m :schema/variant) abstract (-> m :schema/abstract) variant-map (if (keyword? variant) {:schema/variant {:variant variant}} @@ -157,3 +205,29 @@ expand-enums expand-abstracts (vec))) + + +(defn parse-schema2 + [lo-schema & fns] + (let [sch (-> lo-schema + expand-schema-variant2 + expand-schema-abstract2)] + (->> sch + (reduce (fn [res [_ sch]] + (when res + (cond (vector? sch) + (when-some [abstract (first (filter #(-> % :schema/abstract :abstract) sch))] + (some->> (filter #(-> % :schema/variant :variant) sch) + (map #(merge abstract %)) + (map (expand-variant-keys lo-schema fns)) + (concat res))) + + (map? sch) + (let [variant (-> sch :schema/variant :variant)] + (some->> (merge sch {:schema/abstract {:abstract variant}}) + ((expand-variant-keys lo-schema fns)) + (conj res)))))) + []) + expand-enums + expand-abstracts + (vec)))) diff --git a/test/lovii_schema/schema_test.clj b/test/lovii_schema/schema_test.clj new file mode 100644 index 0000000..46a066a --- /dev/null +++ b/test/lovii_schema/schema_test.clj @@ -0,0 +1,111 @@ +(ns lovii-schema.schema-test + (:require [clojure.test :refer :all] + [lovii-schema.core :refer :all] + [lovii-schema.schema :as ls] + [datomic.api :as d] + [schema.core :as s] + [schema.coerce :as coerce] + [lovii-schema.validation :as v] + [lovii-schema.data :as ldata] + [cheshire.core :as json] + [com.rpl.specter :as sp]) + (:import [java.util UUID]) + (:use [com.rpl.specter.macros])) + +(def example + {:users {:schema/variant {:variant :users} + :uuid {:type :uuid :unique :identity :required true} + :name {:type :string :label "Full Name"} + :tags {:type :ref :variants [:tags/set] :cardinality :one} + :social {:type :ref :variants [:social] :cardinality :has-many}} + + :social {:schema/variant {:variant :social :required [#{:social/all-nothing-1 :social/all-nothing-2}]} + :uuid {:type :uuid :unique :identity :required true} + :all-nothing-1 {:type :string} + :all-nothing-2 {:type :string} + :service {:type :enum :values {:twitter "Twitter" + :google "Google" + :facebook "Facebook" + :linkedin "LinkedIn" + :icq "ICQ" + :myspace "MySpace"} + :label "Social Service"} + :account {:type :string :index true :label "Social Account"}} + + :tags [{:schema/abstract {:abstract :tags :required [[:uuid]]} + :uuid {:type :uuid :unique :identity + ;; set above as part of abstract requireds + ; :required true + } + :service {:type :enum :values :social/service} + :one-or-more1 {:type :string} + :one-or-more2 {:type :string} + :label {:type :string :required false + :min-length 2 + :max-length 60 + :regex ".*3.*" + :index true + :label "Label"} + :inactive {:type :boolean :required false :index true :default false}} + + ;; Test the one or more required with :tag instead of setting to :required true + {:schema/variant {:variant :tags/set :required [[:one-or-more1 :one-or-more2]]} + :tags {:type :ref :required false + :cardinality :has-many + :variants [:tags/leaf]}} + {:schema/variant {:variant :tags/leaf} + :tag {:type :string :required true :index true}}]}) + +(def variant-pre + { + :users1 {:schema/variant :users1} ; should be expanded + :users2 {:schema/variant {:variant :users2}} + :users3 [{:schema/variant :users3}] ; should be expanded + :users4 [{:schema/variant {:variant :users4}} ] + }) + +(def variant-after + {:users1 {:schema/variant {:variant :users1}} + :users2 {:schema/variant {:variant :users2}} + :users3 [{:schema/variant {:variant :users3}}] + :users4 [{:schema/variant {:variant :users4}}]}) + +(deftest expand-schema-variant-test + (testing "expand" + (is (= variant-after + (ls/expand-schema-variant2 variant-pre)))) + (testing "parse" + (let [p1 (ls/parse-schema variant-pre) + p2 (ls/parse-schema2 variant-pre)] + (is (map? p1)) + (is (= p1 p2)) + (is (= p1 variant-after))))) + +(def abstract-pre + {:users1 {:schema/abstract :users1} ; should be expanded + :users2 {:schema/abstract {:abstract :users2}} + :users3 [{:schema/abstract :users3}] ; should be expanded + :users4 [{:schema/abstract {:abstract :users4}}]}) + +(def abstract-after + {:users1 {:schema/abstract {:abstract :users1}} + :users2 {:schema/abstract {:abstract :users2}} + :users3 [{:schema/abstract {:abstract :users3}}] + :users4 [{:schema/abstract {:abstract :users4}}]}) + +(deftest expand-schema-abstract-test + (testing "expand" + (is (= abstract-after + (ls/expand-schema-abstract2 abstract-pre)))) + (testing "parse" + (let [p1 (ls/parse-schema abstract-pre) + p2 (ls/parse-schema2 abstract-pre)] + (is (map? p1)) + (is (= p1 p2)) + (is (= p1 abstract-after))))) + +(comment + (ls/parse-schema variant-pre) + (ls/parse-schema2 variant-pre) + (ls/parse-schema example) + (ls/parse-schema2 example))