You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
260 lines
8.6 KiB
260 lines
8.6 KiB
(ns wanijo.instance.db
|
|
(:require [clojure.spec.alpha :as spec]
|
|
[wanijo.infra.neo4j :as neo4j]
|
|
[wanijo.instance.domain :as domain-instance]
|
|
[wanijo.tag.db :as db-tag]
|
|
[wanijo.instance.revision.db :as db-rev]))
|
|
|
|
(neo4j/defquery findy-by-schema
|
|
"MATCH (i:instance)-[:of]->(s:schema)
|
|
WHERE s.uuid = $uuid
|
|
OPTIONAL MATCH
|
|
(i)-[:tagged_with]->(t:tag)
|
|
OPTIONAL MATCH
|
|
(i)<-[:of]-(p:property),
|
|
(p)-[:of]->(a:attribute)
|
|
RETURN i, t, p, a")
|
|
(defn flatten-grouped-rows [instance grouped-rows]
|
|
{:post [(spec/assert ::domain-instance/instance-with-tags-and-props %)]}
|
|
(assoc instance
|
|
:tags (->> grouped-rows
|
|
(map :t)
|
|
(filter some?)
|
|
distinct)
|
|
:properties (->> grouped-rows
|
|
(filter #(some? (:p %)))
|
|
(map #(assoc (:p %)
|
|
:attribute (:a %)))
|
|
distinct)))
|
|
(defn find-by-schema! [schema-uuid]
|
|
{:post [(spec/assert ::domain-instance/instances-with-tags-and-props %)]}
|
|
(->> (neo4j/exec-query! findy-by-schema
|
|
{:uuid schema-uuid})
|
|
(group-by :i)
|
|
(map #(flatten-grouped-rows (key %) (val %)))
|
|
(sort-by :name)))
|
|
|
|
(neo4j/defquery create-instance
|
|
"MATCH (s:schema {uuid: $schema_uuid}),
|
|
(u:user {uuid: $user_uuid})
|
|
CREATE (i:instance {uuid: $uuid})-[:of]->(s),
|
|
(i)-[:created_by]->(u)
|
|
SET i.name = $name,
|
|
i.created_at = $created_at,
|
|
i.updated_at = $created_at")
|
|
(neo4j/defquery create-property
|
|
"MATCH (i:instance {uuid: $uuid}),
|
|
(a:attribute {uuid: $attr_uuid})
|
|
CREATE (p:property {uuid: $prop_uuid})-[:of]->(i),
|
|
(p)-[:of]->(a)
|
|
SET p.value = $value,
|
|
p.created_at = $created_at,
|
|
p.updated_at = $updated_at")
|
|
(defn create! [user-uuid
|
|
schema-uuid
|
|
{:keys [name properties]}]
|
|
(let [instance-uuid (neo4j/uuid)
|
|
now (neo4j/now-str)
|
|
instance-tuple [create-instance
|
|
{:schema_uuid schema-uuid
|
|
:name name
|
|
:uuid instance-uuid
|
|
:created_at now
|
|
:user_uuid user-uuid}]
|
|
prop-tuples (for [{:keys [attribute value]} properties]
|
|
[create-property
|
|
{:uuid instance-uuid
|
|
:attr_uuid (:uuid attribute)
|
|
:prop_uuid (neo4j/uuid)
|
|
:value value
|
|
:created_at now
|
|
:updated_at now}])]
|
|
(apply neo4j/exec-queries!
|
|
(concat [instance-tuple]
|
|
prop-tuples))))
|
|
|
|
(neo4j/defquery find-by-uuid
|
|
"MATCH (i:instance {uuid: $uuid})-[:of]->(s:schema)
|
|
RETURN i, s")
|
|
(defn find-by-uuid! [uuid]
|
|
{:post [(spec/assert ::domain-instance/instance-with-schema %)]}
|
|
(->> (neo4j/exec-query! find-by-uuid
|
|
{:uuid uuid})
|
|
(map #(assoc (:i %)
|
|
:schema
|
|
(:s %)))
|
|
first))
|
|
|
|
(neo4j/defquery find-properties
|
|
"MATCH (i:instance {uuid: $uuid}),
|
|
(p:property)-[:of]->(i),
|
|
(p)-[:of]->(a:attribute)
|
|
RETURN p, a
|
|
ORDER BY a.name")
|
|
(defn find-properties! [uuid]
|
|
(map #(assoc (:p %)
|
|
:attribute
|
|
(:a %))
|
|
(neo4j/exec-query! find-properties
|
|
{:uuid uuid})))
|
|
|
|
(neo4j/defquery edit-instance
|
|
"MATCH (i:instance {uuid: $uuid})
|
|
SET i.name = $name,
|
|
i.updated_at = $updated_at")
|
|
(neo4j/defquery edit-property
|
|
"MATCH (i:instance {uuid: $instance_uuid}),
|
|
(a:attribute {uuid: $attribute_uuid})
|
|
MERGE (p:property {uuid: $uuid})-[:of]->(i)
|
|
MERGE (p)-[:of]->(a)
|
|
ON CREATE SET p.created_at = $now,
|
|
p.updated_at = $now,
|
|
p.value = $value
|
|
ON MATCH SET p.updated_at = $now,
|
|
p.value = $value")
|
|
(defn instance->prop-tuples [instance]
|
|
{:post [(spec/assert ::domain-instance/prop-tuple %)]}
|
|
(map (fn [prop]
|
|
(let [prop-uuid (:uuid prop)
|
|
uuid (if (empty? prop-uuid)
|
|
(neo4j/uuid)
|
|
prop-uuid)]
|
|
[edit-property
|
|
{:uuid uuid
|
|
:now (neo4j/now-str)
|
|
:value (:value prop)
|
|
:instance_uuid (:uuid instance)
|
|
:attribute_uuid (-> prop :attribute :uuid)}]))
|
|
(:properties instance)))
|
|
(defn edit! [instance revision]
|
|
(let [prop-tuples (instance->prop-tuples instance)]
|
|
(apply neo4j/exec-queries!
|
|
(concat [[edit-instance
|
|
{:uuid (:uuid instance)
|
|
:name (:name instance)
|
|
:updated_at (neo4j/now-str)}]]
|
|
prop-tuples
|
|
(db-rev/revision-queries revision)))))
|
|
|
|
(comment
|
|
(db-rev/revision-queries
|
|
{:instance-name "dings"
|
|
:instance-uuid "4711"
|
|
:properties [{:type "string"
|
|
:value "dings-prop"}]}))
|
|
|
|
(neo4j/defquery delete
|
|
"MATCH (i:instance {uuid: $uuid}),
|
|
(i)-[ic:of]->(s:schema),
|
|
(i)-[cb:created_by]->(:user)
|
|
OPTIONAL MATCH
|
|
(p:property)-[pc:of]->(i),
|
|
(p)-[pac:of]->(a:attribute)
|
|
OPTIONAL MATCH
|
|
(i)-[tw:tagged_with]->()
|
|
OPTIONAL MATCH
|
|
(i)-[l:link]-()
|
|
OPTIONAL MATCH
|
|
(i)<-[ric:of]-(rev:revision)
|
|
OPTIONAL MATCH
|
|
(rev_prop:rev_property)-[rpc:of]->(rev)
|
|
DELETE pac, pc, cb, ic, p,
|
|
l, tw, i, ric,
|
|
rpc, rev_prop, rev")
|
|
(defn delete! [uuid]
|
|
(neo4j/exec-query! delete {:uuid uuid}))
|
|
|
|
(defn group-by-link-and-assoc-tags [uuid query direction]
|
|
(->> (neo4j/exec-query! query {:uuid uuid})
|
|
(group-by #(hash-map :link (:link %)
|
|
:schema (:schema %)
|
|
direction (direction %)))
|
|
(map (fn [[link tags]]
|
|
(let [tags (map :tag tags)]
|
|
(assoc link
|
|
:tags (filter some? tags)))))
|
|
(sort-by (juxt #(-> % :schema :name)
|
|
#(-> % direction :name)
|
|
#(-> % direction :created_at)))))
|
|
|
|
(neo4j/defquery outgoing-links
|
|
"MATCH (inst:instance {uuid: $uuid}),
|
|
(inst)-[link:link]->(target:instance),
|
|
(target)-[:of]->(schema:schema)
|
|
OPTIONAL MATCH
|
|
(target)-[:tagged_with]->(tag:tag)
|
|
RETURN link, target, schema, tag")
|
|
(defn outgoing-links! [uuid]
|
|
{:post [(spec/assert ::domain-instance/links-out %)]}
|
|
(group-by-link-and-assoc-tags uuid outgoing-links :target))
|
|
|
|
(neo4j/defquery incoming-links
|
|
"MATCH (inst:instance {uuid: $uuid}),
|
|
(inst)<-[link:link]-(source:instance),
|
|
(source)-[:of]->(schema:schema)
|
|
OPTIONAL MATCH
|
|
(source)-[:tagged_with]->(tag:tag)
|
|
RETURN link, source, schema, tag
|
|
ORDER BY schema.name, source.name, source.created_at")
|
|
(defn incoming-links! [uuid]
|
|
{:post [(spec/assert ::domain-instance/links-in %)]}
|
|
(group-by-link-and-assoc-tags uuid incoming-links :source))
|
|
|
|
(defn full-instance-by-uuid! [uuid]
|
|
{:post [(spec/assert ::domain-instance/full-instance %)]}
|
|
(assoc (find-by-uuid! uuid)
|
|
:properties
|
|
(find-properties! uuid)
|
|
:links-out
|
|
(outgoing-links! uuid)
|
|
:links-in
|
|
(incoming-links! uuid)
|
|
:tags
|
|
(db-tag/tags-by-instance! uuid)))
|
|
|
|
(neo4j/defquery is-starred
|
|
"MATCH (u:user {uuid: $user_uuid}),
|
|
(i:instance {uuid: $uuid})
|
|
RETURN EXISTS((i)-[:starred_by]->(u)) AS starred")
|
|
(defn is-starred! [uuid user-uuid]
|
|
(-> (neo4j/exec-query! is-starred
|
|
{:user_uuid user-uuid
|
|
:uuid uuid})
|
|
first
|
|
:starred))
|
|
|
|
(neo4j/defquery mark-starred
|
|
"MATCH (i:instance {uuid: $uuid}),
|
|
(u:user {uuid: $user_uuid})
|
|
MERGE (i)-[s:starred_by]->(u)
|
|
ON CREATE
|
|
SET s.created_at = $now")
|
|
(defn mark-starred! [uuid user-uuid]
|
|
(neo4j/exec-query! mark-starred
|
|
{:uuid uuid
|
|
:user_uuid user-uuid
|
|
:now (neo4j/now-str)}))
|
|
|
|
(neo4j/defquery remove-starred
|
|
"MATCH (:instance {uuid: $uuid})
|
|
-[s:starred_by]->
|
|
(:user {uuid: $user_uuid})
|
|
DELETE s")
|
|
(defn remove-starred! [uuid user-uuid]
|
|
(neo4j/exec-query! remove-starred
|
|
{:uuid uuid
|
|
:user_uuid user-uuid}))
|
|
|
|
(neo4j/defquery starred-by-user
|
|
"MATCH (u:user {uuid: $user_uuid})
|
|
<-[s:starred_by]-
|
|
(i:instance)
|
|
RETURN i, s
|
|
ORDER BY s.created_at DESC")
|
|
(defn starred-by-user! [user-uuid]
|
|
(map #(assoc (:i %)
|
|
:starred_at (-> % :s :created_at))
|
|
(neo4j/exec-query! starred-by-user
|
|
{:user_uuid user-uuid})))
|
|
|