Skip to content

Commit 2cde58f

Browse files
author
Paula Gearon
committed
Need to test with rule predicate initialization
1 parent 3f51393 commit 2cde58f

File tree

1 file changed

+108
-0
lines changed

1 file changed

+108
-0
lines changed
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
(ns ^{:doc "Functions for generating a user schema for Datomic."
2+
:author "Paula Gearon"}
3+
naga.storage.datomic.schema
4+
(:require [clojure.string :as s]
5+
[naga.util :as u])
6+
(:import [datomic Peer]
7+
[java.util Map List]))
8+
9+
10+
(defn- convert-typename
11+
"Ensures that user-friendly typenames are "
12+
[t]
13+
({"map" ["ref" :map]
14+
"array" ["ref" :array]} t [t nil]))
15+
16+
(defn- simple-def
17+
[[_ [[nm t]]]]
18+
(let [[tp ot] (convert-typename t)
19+
sch {:db/id (Peer/tempid :db.part/db)
20+
:db/ident (keyword nm)
21+
:db/valueType (keyword "db.type" tp)
22+
:db/cardinality :db.cardinality/one
23+
:db.install/_attribute :db.part/db}]
24+
(if ot (assoc sch :naga/json.type ot) sch)))
25+
26+
(defn- complex-def
27+
[[nm ps]]
28+
(let [nk-id (Peer/tempid :db.part/db)
29+
attributes (map
30+
(fn [[_ t]]
31+
(let [[tp ot] (convert-typename t)
32+
sch {:db/id (Peer/tempid :db.part/db)
33+
:db/ident (keyword (str nm "." tp))
34+
:db/valueType (keyword "db.type" tp)
35+
:db/cardinality :db.cardinality/one
36+
:naga/original nk-id
37+
:db.install/_attribute :db.part/db}]
38+
(if ot (assoc sch :naga/json.type ot) sch)))
39+
ps)]
40+
(cons
41+
{:db/id nk-id
42+
:db/ident (keyword nm)
43+
:naga/attributes (map :db/id attributes)}
44+
attributes)))
45+
46+
(defn- attribute-data
47+
"Generates data for new attribute definitions, based on a sequence of name/type string pairs.
48+
Returns a sequence of transaction data sequences, which will need to be transacted in order."
49+
[pairs]
50+
(let [grouped (into [] (map (fn [[k v]] [k (vec (set v))]) (group-by first pairs)))
51+
[simple-pairs complex-pairs] (u/divide #(= 1 (count (second %))) grouped)]
52+
(concat
53+
(map simple-def simple-pairs)
54+
(mapcat complex-def complex-pairs))))
55+
56+
(defn pair-file-to-attributes
57+
"Generates data for new attribute definitions, based on a file of attribute/type pairs."
58+
[file-text]
59+
(->> (s/split file-text #"\n")
60+
(map #(s/split % #"\W+"))
61+
attribute-data))
62+
63+
(defprotocol Dataschema
64+
(typename [data] "Returns the name of a JSON type")
65+
(schema-from [data xfr] "Generate a schema out of data, and add to the xfr transactor"))
66+
67+
(def special-cases
68+
{"integer" "long"})
69+
70+
(extend-protocol Dataschema
71+
Map
72+
(typename [jmap] "map")
73+
(schema-from [jmap xfr]
74+
(doseq [[k v] jmap]
75+
(if-let [t (typename v)]
76+
(xfr [(name k) t]))
77+
(schema-from v xfr)))
78+
List
79+
(typename [jlist] "array")
80+
(schema-from [jlist xfr]
81+
(doseq [l jlist] (schema-from l xfr)))
82+
nil
83+
(typename [n])
84+
(schema-from [n xfr])
85+
Object
86+
(typename [jdata]
87+
(let [tn (s/lower-case (.getSimpleName (class jdata)))]
88+
(special-cases tn tn)))
89+
(schema-from [data xfr]))
90+
91+
(defn extract-types
92+
"Return a sequence of property/type pairs identified in JSON.
93+
JSON must be a sequence of entity maps."
94+
[json-data]
95+
(let [tx (fn [xf]
96+
(fn
97+
([] (xf))
98+
([result] (xf result))
99+
([result input]
100+
(schema-from input (partial xf result)))))]
101+
(when-not (sequential? json-data)
102+
(throw (ex-info "Invalid JSON sequence" {:data json-data})))
103+
(sequence tx json-data)))
104+
105+
(defn auto-schema
106+
"Determine a Datomic schema for a provided JSON structure."
107+
[json-data]
108+
(attribute-data (extract-types json-data)))

0 commit comments

Comments
 (0)