From aba2175070925884697a56816ecd8b9db48e449f Mon Sep 17 00:00:00 2001 From: Joshua Heimbach Date: Thu, 15 Dec 2016 16:43:13 +0000 Subject: [PATCH 01/22] Add path/class? to determine if a path ends at the class level --- src/imcljs/core.cljs | 20 +++++++++++++------- src/imcljs/path.cljs | 10 ++++++++++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/imcljs/core.cljs b/src/imcljs/core.cljs index dd7e1c9..1dae21a 100644 --- a/src/imcljs/core.cljs +++ b/src/imcljs/core.cljs @@ -119,17 +119,23 @@ :select ["Gene.symbol" "Gene.secondaryIdentifier"] :orderBy [{:symbol "asc"}]}) - (go - (let [fm (assoc flymine-beta :token ( true + (class im-model `Gene.diseases.name`) + => false" + [model path] + (let [walked (walk model path)] + (not (contains? (last walked) :type)))) + (defn trim-to-last-class "Returns a path string trimmed to the last class (trim-to-last-class im-model `Gene.homologues.homologue.symbol`) From 0e6071ffe1153aa7a10faf71ee5476cf51b55170 Mon Sep 17 00:00:00 2001 From: Joshua Heimbach Date: Thu, 15 Dec 2016 18:02:52 +0000 Subject: [PATCH 02/22] Fix path/friendly fn to show paths as readable strings --- src/imcljs/core.cljs | 3 ++- src/imcljs/path.cljs | 13 ++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/imcljs/core.cljs b/src/imcljs/core.cljs index 1dae21a..3dc1aee 100644 --- a/src/imcljs/core.cljs +++ b/src/imcljs/core.cljs @@ -119,9 +119,10 @@ :select ["Gene.symbol" "Gene.secondaryIdentifier"] :orderBy [{:symbol "asc"}]}) + ;(go ; (let [model ( :Gene" [model class-kw field-kw] - (keyword (:referencedType (get (apply merge (map (get-in model [:classes class-kw])[:references :collections])) field-kw)))) + (keyword (:referencedType (get (apply merge (map (get-in model [:classes class-kw]) [:references :collections])) field-kw)))) (defn is-attribute [class value] (get-in class [:attributes value])) @@ -92,7 +92,10 @@ (apply merge (map (get-in model [:classes class-kw]) [:references :collections]))) (defn friendly - ([model path] - (friendly model (if (string? path) (split-path path) path) [])) - ([model [class-kw & [path & remaining]] trail] - (get-in (relationships model class-kw) [path :referencedType]))) \ No newline at end of file + "Returns a path as a strong" + ([model path & [exclude-root?]] + (reduce + (fn [total next] + (str total (if total " > ") (or (:displayName next) (:name next)))) + nil + (if exclude-root? (rest (walk model path)) (walk model path))))) \ No newline at end of file From a9c4b30d3bc2ded0f42738490c51e812afdeb087 Mon Sep 17 00:00:00 2001 From: Joshua Heimbach Date: Fri, 16 Dec 2016 17:12:59 +0000 Subject: [PATCH 03/22] walk fn supports paths containing subclasses --- src/imcljs/core.cljs | 4 ++-- src/imcljs/path.cljs | 33 ++++++++++++++++++++------------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/imcljs/core.cljs b/src/imcljs/core.cljs index 3dc1aee..4622ea2 100644 --- a/src/imcljs/core.cljs +++ b/src/imcljs/core.cljs @@ -119,10 +119,10 @@ :select ["Gene.symbol" "Gene.secondaryIdentifier"] :orderBy [{:symbol "asc"}]}) - ;(go ; (let [model ( Gene.organism.shortName" [path-str] (join "." (map name path-str))) -(defn referenced-class +(defn referenced-type "Given a model, a class, and a collection or reference, return the class of the collection or reference. (referenced-class im-model :Gene :homologues) => :Gene" - [model class-kw field-kw] + [model field-kw class-kw] (keyword (:referencedType (get (apply merge (map (get-in model [:classes class-kw]) [:references :collections])) field-kw)))) +(defn referenced-class + "Given a model, a reference/collection, and a class, + return the superclass of the reference/collection. + In the example :tissue is an attribute of the subclass :FlyAtlasResult + (referenced-class im-model :MicroArrayResult :tissue) + => :Tissue" + [model field-kw class-kw] + (.log js/console field-kw class-kw) + (->> (:classes model) + (filter (fn [[_ {:keys [extends]}]] (some (partial = class-kw) (map keyword extends)))) + (map first) + (cons class-kw) + (map (partial referenced-type model field-kw)) + (filter identity) + first)) + (defn is-attribute [class value] (get-in class [:attributes value])) @@ -44,7 +52,7 @@ ([model [class-kw & [path & remaining]] trail] (if-let [attribute (is-attribute (get-in model [:classes class-kw]) path)] (reduce conj trail [(get-in model [:classes class-kw]) attribute]) - (if-let [class (referenced-class model class-kw path)] + (if-let [class (referenced-class model path class-kw)] (recur model (conj remaining class) (conj trail (get-in model [:classes class-kw]))) (if-not path (if-let [final (get-in model [:classes class-kw])] @@ -55,8 +63,7 @@ (attribute-type im-model `Gene.organism.shortName`) => java.lang.String" [model path] - (if-let [walked (walk model path)] - (get path-types (:type (last walked))))) + (:type (last (walk model path)))) (defn class "Returns the class represented by the path. From 662443575b891497053bd3c8d5b5c013e2ba20de Mon Sep 17 00:00:00 2001 From: Joshua Heimbach Date: Fri, 16 Dec 2016 17:22:11 +0000 Subject: [PATCH 04/22] General refactoring and cleanup --- src/imcljs/core.cljs | 23 +++++------------------ src/imcljs/path.cljs | 15 ++++++--------- 2 files changed, 11 insertions(+), 27 deletions(-) diff --git a/src/imcljs/core.cljs b/src/imcljs/core.cljs index 4622ea2..b0275e1 100644 --- a/src/imcljs/core.cljs +++ b/src/imcljs/core.cljs @@ -8,13 +8,13 @@ [imcljs.save :as save] [imcljs.entity :as entity])) - - - - (enable-console-print!) (defn on-js-reload [] + + ; Everything in this fn is for testing and will go away when I figured out why + ; asynch events are misbehaving + (def flymine {:root "beta.flymine.org/beta" :model {:name "genomic"}}) @@ -38,8 +38,6 @@ :op "ISA" :values ["Exon" "Intron" "Gene"]}]}) - - (def bigr {:from "SequenceFeature" :select ["SequenceFeature.id" "SequenceFeature.name" @@ -57,7 +55,6 @@ :op "=" :value "D. melanogaster"}]}) - (def ids-constraint-shortcut {:from "Gene" :select ["Gene.symbol"] @@ -121,10 +118,7 @@ ;(go ; (let [model ( Gene.organism.shortName" [path-str] (join "." (map name path-str))) +(defn relationships + "Given a model and a class, return its collections and references." + [model class-kw] + (apply merge (map (get-in model [:classes class-kw]) [:references :collections]))) + (defn referenced-type "Given a model, a class, and a collection or reference, return the class of the collection or reference. (referenced-class im-model :Gene :homologues) => :Gene" [model field-kw class-kw] - (keyword (:referencedType (get (apply merge (map (get-in model [:classes class-kw]) [:references :collections])) field-kw)))) + (keyword (:referencedType (get (relationships model class-kw) field-kw)))) (defn referenced-class "Given a model, a reference/collection, and a class, @@ -28,7 +33,6 @@ (referenced-class im-model :MicroArrayResult :tissue) => :Tissue" [model field-kw class-kw] - (.log js/console field-kw class-kw) (->> (:classes model) (filter (fn [[_ {:keys [extends]}]] (some (partial = class-kw) (map keyword extends)))) (map first) @@ -91,13 +95,6 @@ (let [done (take-while #(does-not-contain? % :type) (walk model path))] (join-path (take (count done) (split-path path))))) -(defn relationships - "Given a model, a class, and a collection or reference, return the class of the collection or reference. - (referenced-class im-model :Gene :homologues) - => :Gene" - [model class-kw] - (apply merge (map (get-in model [:classes class-kw]) [:references :collections]))) - (defn friendly "Returns a path as a strong" ([model path & [exclude-root?]] From 291b70403335807d2dc9ab62f472bece3bf16d45 Mon Sep 17 00:00:00 2001 From: Joshua Heimbach Date: Mon, 19 Dec 2016 14:49:45 +0000 Subject: [PATCH 05/22] Better subclass detection in walk fn --- src/imcljs/core.cljs | 9 ++++++--- src/imcljs/path.cljs | 17 ++++++++++++++++- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/imcljs/core.cljs b/src/imcljs/core.cljs index b0275e1..e6abdb7 100644 --- a/src/imcljs/core.cljs +++ b/src/imcljs/core.cljs @@ -116,9 +116,12 @@ :select ["Gene.symbol" "Gene.secondaryIdentifier"] :orderBy [{:symbol "asc"}]}) - ;(go - ; (let [model ( :Gene" [model field-kw class-kw] + ;(.log js/console "CHECKING REFERECNE TYPE" field-kw class-kw) + ;(.log js/console "RETURNED " (keyword (:referencedType (get (relationships model class-kw) field-kw)))) (keyword (:referencedType (get (relationships model class-kw) field-kw)))) (defn referenced-class @@ -44,6 +48,17 @@ (defn is-attribute [class value] (get-in class [:attributes value])) +(defn extended-class [model field-kw class-kw] + ; Given a field keyword and a class kw, return the class or subclass that has the field. + ; (extended-class model :affyCall :MicroArrayResult + ; => :FlyAtlasResult + (->> (:classes model) + (filter (fn [[_ {:keys [extends]}]] (some (partial = class-kw) (map keyword extends)))) + (filter (fn [[_ class-details]] + (get (apply merge (map class-details [:attributes :references :collections])) field-kw))) + first + first)) + (defn walk "Return a vector representing each part of path. If any part of the path is unresolvable then a nil is returned. @@ -54,7 +69,7 @@ ([model path] (walk model (if (string? path) (split-path path) path) [])) ([model [class-kw & [path & remaining]] trail] - (if-let [attribute (is-attribute (get-in model [:classes class-kw]) path)] + (if-let [attribute (is-attribute (get-in model [:classes (extended-class model path class-kw)]) path)] (reduce conj trail [(get-in model [:classes class-kw]) attribute]) (if-let [class (referenced-class model path class-kw)] (recur model (conj remaining class) (conj trail (get-in model [:classes class-kw]))) From b031a7eeaa6238b3ea9863da970c410c6218d068 Mon Sep 17 00:00:00 2001 From: Joshua Heimbach Date: Mon, 19 Dec 2016 16:28:08 +0000 Subject: [PATCH 06/22] Fix bug in relationships fn --- src/imcljs/path.cljs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/imcljs/path.cljs b/src/imcljs/path.cljs index 593c585..0cc27dc 100644 --- a/src/imcljs/path.cljs +++ b/src/imcljs/path.cljs @@ -17,17 +17,13 @@ (defn relationships "Given a model and a class, return its collections and references." [model class-kw] - ;(.log js/console "got relationships" class-kw) - ;(.log js/console "relationships returning" (apply merge (map (get-in model [:classes class-kw]) [:references :collections]))) - (apply merge (map (get-in model [:classes class-kw]) [:references :collections]))) + (map (get-in model [:classes class-kw]) [:references :collections])) (defn referenced-type "Given a model, a class, and a collection or reference, return the class of the collection or reference. (referenced-class im-model :Gene :homologues) => :Gene" [model field-kw class-kw] - ;(.log js/console "CHECKING REFERECNE TYPE" field-kw class-kw) - ;(.log js/console "RETURNED " (keyword (:referencedType (get (relationships model class-kw) field-kw)))) (keyword (:referencedType (get (relationships model class-kw) field-kw)))) (defn referenced-class From 070133072a18b885aee38ed93b0396f7a10ed275 Mon Sep 17 00:00:00 2001 From: Joshua Heimbach Date: Tue, 20 Dec 2016 13:23:56 +0000 Subject: [PATCH 07/22] Walk fn is comprised of more robust functions (fixes bug) --- src/imcljs/core.cljs | 139 +------------------------------------------ src/imcljs/path.cljs | 48 +++++++++------ 2 files changed, 32 insertions(+), 155 deletions(-) diff --git a/src/imcljs/core.cljs b/src/imcljs/core.cljs index e6abdb7..8c18f48 100644 --- a/src/imcljs/core.cljs +++ b/src/imcljs/core.cljs @@ -11,141 +11,4 @@ (enable-console-print!) (defn on-js-reload [] - - ; Everything in this fn is for testing and will go away when I figured out why - ; asynch events are misbehaving - - (def flymine {:root "beta.flymine.org/beta" - :model {:name "genomic"}}) - - (def flymine-beta {:root "beta.flymine.org/beta" - :model {:name "genomic"}}) - - (def mousemine {:root "www.mousemine.org/mousemine" - :model {:name "genomic"}}) - - (def a-query {:select ["Gene.symbol" "Gene.secondaryIdentifier" "Gene.homologues.homologue.name"] - :orderBy [{:symbol "asc"}] - :where [{:path "symbol" - :op "=" - :value "ab*"}]}) - - - (def region {:from "SequenceFeature" - :select ["SequenceFeature.id"] - :orderBy [["SequenceFeature.id" "asc"]] - :where [{:path "SequenceFeature" - :op "ISA" - :values ["Exon" "Intron" "Gene"]}]}) - - (def bigr {:from "SequenceFeature" - :select ["SequenceFeature.id" - "SequenceFeature.name" - "SequenceFeature.primaryIdentifier" - "SequenceFeature.symbol" - "SequenceFeature.chromosomeLocation.start" - "SequenceFeature.chromosomeLocation.end" - "SequenceFeature.chromosomeLocation.locatedOn.primaryIdentifier"] - :where [{:path "SequenceFeature.chromosomeLocation" - :op "OVERLAPS" - :values ["2L:14615455..14619002" - "2R:5866646..5868384" - "3R:2578486..2580016"]} - {:path "SequenceFeature.organism.shortName" - :op "=" - :value "D. melanogaster"}]}) - - (def ids-constraint-shortcut - {:from "Gene" - :select ["Gene.symbol"] - :where [{:path "Gene" - :ids [1000100 1000781 1001050 1001183 1001292]}]}) - - (def subclass-query - {:from "OntologyAnnotation", - :select ["subject.primaryIdentifier" - "subject.symbol" - "evidence.baseAnnotations.subject.symbol" - "evidence.baseAnnotations.subject.background.name" - "evidence.baseAnnotations.subject.zygosity" - "ontologyTerm.identifier" - "ontologyTerm.name"], - :orderBy [{:path "subject.symbol", :direction "ASC"}], - :where [{:path "ontologyTerm.parents", :type "MPTerm"} - {:path "ontologyTerm", :type "MPTerm"} - {:path "subject", :type "SequenceFeature"} - {:path "evidence.baseAnnotations.subject", :type "Genotype"} - {:path "ontologyTerm.parents", :op "LOOKUP", :value "*circulating glucose*", :code "A"}]}) - - (def subclass-query-2 - {:name "Lookup_MPhenotype", - :title "Lookup --> Mammalian phenotypes (MP terms)", - :description "Returns MP terms whose names match the specified search terms.", - :constraintLogic "A and B", - :from "MPTerm", - :select ["name" "identifier" "description"], - :orderBy [{:path "name", :direction "ASC"}], - :where [{:path "obsolete", - :op "=", - :value "false", :code "B", - :editable false, - :switched "LOCKED", - :switchable false} - {:path "name", - :op "CONTAINS", - :value "hemoglobin", - :code "A", - :editable true, - :switched "LOCKED", - :switchable false}]}) - - (def constraint-query - {:from "Gene" - :select ["Gene.symbol" "Gene.secondaryIdentifier"] - :orderBy [{:symbol "asc"}] - :where [{:path "Gene" - :op "IN" - :value "PL FlyAtlas_maleglands_top"} - {:path "Gene.symbol" - :op "<=" - :value "100" - :code "A"}]}) - - (def big-query - {:from "Gene" - :select ["Gene.symbol" "Gene.secondaryIdentifier"] - :orderBy [{:symbol "asc"}]}) - - ;Gene.downstreamIntergenicRegion.adjacentGenes.microArrayResults.affyCall - ;"Gene.downstreamIntergenicRegion.adjacentGenes.microArrayResults.affyCall" - - (go - (let [model ( :Gene" [model field-kw class-kw] + ;(.log js/console "referenced-type given" field-kw class-kw) + ;(.log js/console "which produces" (keyword (:referencedType (get (relationships model class-kw) field-kw)))) (keyword (:referencedType (get (relationships model class-kw) field-kw)))) (defn referenced-class @@ -41,18 +46,26 @@ (filter identity) first)) -(defn is-attribute [class value] - (get-in class [:attributes value])) +(defn referenced-values + "Given a model, a class, and a collection or reference, return the class of the collection or reference. + (referenced-class im-model :Gene :homologues) + => :Gene" + [model field-kw class-kw] + (get (relationships model class-kw) field-kw)) -(defn extended-class [model field-kw class-kw] - ; Given a field keyword and a class kw, return the class or subclass that has the field. - ; (extended-class model :affyCall :MicroArrayResult - ; => :FlyAtlasResult +(defn class-value + "Given a model and a field, return that field from the data model. + A field can be a reference, a collection, or an attribute + In the example :tissue is an attribute of the subclass :FlyAtlasResult + (referenced-class im-model :MicroArrayResult :tissue) + => :Tissue" + [model class-kw field-kw] (->> (:classes model) (filter (fn [[_ {:keys [extends]}]] (some (partial = class-kw) (map keyword extends)))) - (filter (fn [[_ class-details]] - (get (apply merge (map class-details [:attributes :references :collections])) field-kw))) - first + (map first) + (cons class-kw) + (map (partial referenced-values model field-kw)) + (filter identity) first)) (defn walk @@ -65,13 +78,13 @@ ([model path] (walk model (if (string? path) (split-path path) path) [])) ([model [class-kw & [path & remaining]] trail] - (if-let [attribute (is-attribute (get-in model [:classes (extended-class model path class-kw)]) path)] - (reduce conj trail [(get-in model [:classes class-kw]) attribute]) - (if-let [class (referenced-class model path class-kw)] - (recur model (conj remaining class) (conj trail (get-in model [:classes class-kw]))) - (if-not path - (if-let [final (get-in model [:classes class-kw])] - (conj trail final))))))) + (let [cv (class-value model class-kw path)] + (if remaining + (if (contains? cv :referencedType) + (recur model + (cons (keyword (:referencedType cv)) remaining) + (conj trail (get-in model [:classes class-kw])))) + (conj trail (get-in model [:classes class-kw]) cv))))) (defn data-type "Return the java type of a path representing an attribute. @@ -104,6 +117,7 @@ => Gene.homologues.homologue" [model path] (let [done (take-while #(does-not-contain? % :type) (walk model path))] + (.log js/console "DONE" path (walk model path)) (join-path (take (count done) (split-path path))))) (defn friendly From b68675806cc56f200f3bed6f126f0df922d69ac8 Mon Sep 17 00:00:00 2001 From: Joshua Heimbach Date: Tue, 20 Dec 2016 13:45:33 +0000 Subject: [PATCH 08/22] First test (walk fn) --- test/cljs/imcljs/core_test.cljs | 8 ++++---- test/cljs/imcljs/path_test.cljs | 18 ++++++++++++++++++ test/cljs/imcljs/runner.cljs | 5 +++-- 3 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 test/cljs/imcljs/path_test.cljs diff --git a/test/cljs/imcljs/core_test.cljs b/test/cljs/imcljs/core_test.cljs index 1536ce9..a4d2238 100644 --- a/test/cljs/imcljs/core_test.cljs +++ b/test/cljs/imcljs/core_test.cljs @@ -1,7 +1,7 @@ (ns imcljs.core-test (:require-macros [cljs.core.async.macros :refer [go go-loop]]) (:require [cljs.test :refer-macros [async deftest testing is]] - [cljs.core.async :as async :refer [ Date: Tue, 20 Dec 2016 13:48:45 +0000 Subject: [PATCH 09/22] TravisCI tests --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..eaae894 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,3 @@ +language: clojure +lein: lein2 +script: lein2 doo phantom test once \ No newline at end of file From 35d95972a36f796d7aac9b32c3e6d954e87927be Mon Sep 17 00:00:00 2001 From: Joshua Heimbach Date: Tue, 20 Dec 2016 13:53:22 +0000 Subject: [PATCH 10/22] Kicking off Travis build --- test/cljs/imcljs/runner.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cljs/imcljs/runner.cljs b/test/cljs/imcljs/runner.cljs index fd53a02..ebb2eb6 100644 --- a/test/cljs/imcljs/runner.cljs +++ b/test/cljs/imcljs/runner.cljs @@ -1,6 +1,6 @@ (ns imcljs.runner (:require [doo.runner :refer-macros [doo-tests]] - [imcljs.core-test] + ;[imcljs.core-test] [imcljs.path-test])) (doo-tests 'imcljs.path-test) From b068a7f4fdc238df3cb002f3a45bc459bdfb0c5e Mon Sep 17 00:00:00 2001 From: Joshua Heimbach Date: Tue, 20 Dec 2016 13:54:43 +0000 Subject: [PATCH 11/22] Remove clojure.string warning --- src/imcljs/internal/utils.cljs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/imcljs/internal/utils.cljs b/src/imcljs/internal/utils.cljs index bffdee1..e519d51 100644 --- a/src/imcljs/internal/utils.cljs +++ b/src/imcljs/internal/utils.cljs @@ -1,4 +1,5 @@ -(ns imcljs.internal.utils) +(ns imcljs.internal.utils + (:require [clojure.string :refer [split]])) (def does-not-contain? (complement contains?)) @@ -10,7 +11,7 @@ (defn append- [text val] (str val text)) -(def alphabet (apply sorted-set (clojure.string/split "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ""))) +(def alphabet (apply sorted-set (split "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ""))) (defn scrub-url "Ensures that a url starts with an http protocol and ends with /service" From 573cb557072e8a4ba96227386764952a45ea9e11 Mon Sep 17 00:00:00 2001 From: Joshua Heimbach Date: Tue, 20 Dec 2016 16:32:38 +0000 Subject: [PATCH 12/22] Fix deconstruct-by-class, more tests --- .gitignore | 1 + src/imcljs/core.cljs | 3 +- src/imcljs/path.cljs | 18 +++++--- test/cljs/imcljs/path_test.cljs | 71 +++++++++++++++++++++++++++++--- test/cljs/imcljs/query_test.cljs | 46 +++++++++++++++++++++ test/cljs/imcljs/runner.cljs | 5 ++- 6 files changed, 128 insertions(+), 16 deletions(-) create mode 100644 test/cljs/imcljs/query_test.cljs diff --git a/.gitignore b/.gitignore index 5129e0a..197f338 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ out .lein-* /resources/public/js /resources/public/js/test +node_modules/ \ No newline at end of file diff --git a/src/imcljs/core.cljs b/src/imcljs/core.cljs index 8c18f48..fbc64a7 100644 --- a/src/imcljs/core.cljs +++ b/src/imcljs/core.cljs @@ -10,5 +10,4 @@ (enable-console-print!) -(defn on-js-reload [] - (.log js/console "Reloading.")) \ No newline at end of file +(defn on-js-reload []) diff --git a/src/imcljs/path.cljs b/src/imcljs/path.cljs index 53fac4d..50005e5 100644 --- a/src/imcljs/path.cljs +++ b/src/imcljs/path.cljs @@ -76,15 +76,22 @@ {:name `Organism`, :collections {...} :attributes {...} {:name `shortName`, :type `java.lang.String`}]" ([model path] - (walk model (if (string? path) (split-path path) path) [])) + (let [p (if (string? path) (split-path path) path)] + (if (= 1 (count p)) + [(get-in model [:classes (first p)])] + (walk model p [])))) ([model [class-kw & [path & remaining]] trail] (let [cv (class-value model class-kw path)] (if remaining - (if (contains? cv :referencedType) + (cond + (contains? cv :referencedType) (recur model (cons (keyword (:referencedType cv)) remaining) (conj trail (get-in model [:classes class-kw])))) - (conj trail (get-in model [:classes class-kw]) cv))))) + (conj trail (get-in model [:classes class-kw]) + (if (contains? cv :referencedType) + (get-in model [:classes (keyword (:referencedType cv))]) + cv)))))) (defn data-type "Return the java type of a path representing an attribute. @@ -98,8 +105,8 @@ (class im-model `Gene.homologues.homologue.symbol`) => :Gene" [model path] - (let [done (take-while #(does-not-contain? % :type) (walk model path))] - (keyword (:name (last done))))) + (let [l (last (take-while #(does-not-contain? % :type) (walk model path)))] + (keyword (or (:referencedType l) (keyword (:name l)))))) (defn class? "Returns true if path is a class. @@ -117,7 +124,6 @@ => Gene.homologues.homologue" [model path] (let [done (take-while #(does-not-contain? % :type) (walk model path))] - (.log js/console "DONE" path (walk model path)) (join-path (take (count done) (split-path path))))) (defn friendly diff --git a/test/cljs/imcljs/path_test.cljs b/test/cljs/imcljs/path_test.cljs index ceb9ad4..185171a 100644 --- a/test/cljs/imcljs/path_test.cljs +++ b/test/cljs/imcljs/path_test.cljs @@ -5,14 +5,73 @@ [imcljs.path :as path] [imcljs.fetch :as fetch])) -(def flymine-beta {:root "beta.flymine.org/beta" - :model {:name "genomic"}}) +(def service {:root "beta.flymine.org/beta" + :model {:name "genomic"}}) -(deftest walk - (testing "Should walk a path and return parts of the model" +(deftest walk-subclass + (testing "Should be able to walk a path that with" (async done (go - (let [model ( Date: Tue, 20 Dec 2016 16:37:04 +0000 Subject: [PATCH 13/22] Badges --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index cf2ae92..b80b89b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # imcljs +[[https://clojars.org/intermine/imcljs][https://img.shields.io/clojars/v/intermine/imcljs.svg]] +[![Build Status](https://travis-ci.org/intermine/imcljs.svg?branch=master)](https://travis-ci.org/intermine/imcljs) + A library for interacting with Intermine's web services. ## Getting Start From 5018a5942a39a7101e5c3551e6f0f2327414a6a7 Mon Sep 17 00:00:00 2001 From: Joshua Heimbach Date: Tue, 20 Dec 2016 16:38:19 +0000 Subject: [PATCH 14/22] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index b80b89b..1650a7d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ # imcljs -[[https://clojars.org/intermine/imcljs][https://img.shields.io/clojars/v/intermine/imcljs.svg]] [![Build Status](https://travis-ci.org/intermine/imcljs.svg?branch=master)](https://travis-ci.org/intermine/imcljs) A library for interacting with Intermine's web services. From d8c97cac15780d646229334df1536a5a807efd48 Mon Sep 17 00:00:00 2001 From: Joshua Heimbach Date: Wed, 1 Feb 2017 13:36:16 +0000 Subject: [PATCH 15/22] Retain constraint logic when converting a query to XML --- src/imcljs/query.cljs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/imcljs/query.cljs b/src/imcljs/query.cljs index f073eb1..59d313e 100644 --- a/src/imcljs/query.cljs +++ b/src/imcljs/query.cljs @@ -107,9 +107,10 @@ [model query] ;(if (nil query) (throw (js/Error. "Oops!"))) (let [query (sterilize-query query) - head-attributes {:model (:name model) - :view (clojure.string/join " " (:select query)) - :sortOrder (clojure.string/join " " (flatten (map (juxt :path :direction) (:orderBy query))))}] + head-attributes (cond-> {:model (:name model) + :view (clojure.string/join " " (:select query))} + (:constraintLogic query) (assoc :constraintLogic (:constraintLogic query)) + (:sortOrder query) (assoc :sortOrder (clojure.string/join " " (flatten (map (juxt :path :direction) (:orderBy query))))))] (str "" (apply str (map (partial map->xmlstr "constraint") (:where query))) ""))) From b4b7404627cc9c5edf8590fa17ab9ad352d0778b Mon Sep 17 00:00:00 2001 From: Joshua Heimbach Date: Tue, 7 Feb 2017 12:28:04 +0000 Subject: [PATCH 16/22] Add fetch/possible-values fn --- project.clj | 2 +- src/imcljs/fetch.cljs | 4 ++++ src/imcljs/query.cljs | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/project.clj b/project.clj index 8324aac..5bc4ca6 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject intermine/imcljs "0.1.13-SNAPSHOT" +(defproject intermine/imcljs "0.1.14-SNAPSHOT" :description "imcljs" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} diff --git a/src/imcljs/fetch.cljs b/src/imcljs/fetch.cljs index ab15878..3a765ca 100644 --- a/src/imcljs/fetch.cljs +++ b/src/imcljs/fetch.cljs @@ -26,6 +26,10 @@ [service query & [options]] (restful :post "/query/results" service (merge {:query query :format "count"} options))) +(defn possible-values + [service path & [options]] + (restful :get "/path/values" service (merge {:path path :format "json"} options))) + ; Assets (defn lists diff --git a/src/imcljs/query.cljs b/src/imcljs/query.cljs index 59d313e..b219b9b 100644 --- a/src/imcljs/query.cljs +++ b/src/imcljs/query.cljs @@ -102,6 +102,8 @@ enforce-views-have-class enforce-origin)) + + (defn ->xml "Returns the stringfied XML representation of an EDN intermine query." [model query] From c0c46470eeae5b9b0cadc532bf961c2c379dfb3d Mon Sep 17 00:00:00 2001 From: Joshua Heimbach Date: Wed, 8 Feb 2017 13:41:23 +0000 Subject: [PATCH 17/22] Rename relationships fn to properties, add actualy relationships and attributes functions --- src/imcljs/path.cljs | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/imcljs/path.cljs b/src/imcljs/path.cljs index 50005e5..8071a72 100644 --- a/src/imcljs/path.cljs +++ b/src/imcljs/path.cljs @@ -14,13 +14,10 @@ => Gene.organism.shortName" [path-str] (join "." (map name path-str))) -(defn relationships - "Given a model and a class, return its collections and references." +(defn properties + "Given a model and a class, return its attributes, references and collections." [model class-kw] - ;(.log js/console "RELS" (apply merge (map (get-in model [:classes class-kw]) [:references :collections]))) - (apply merge (map (get-in model [:classes class-kw]) [:attributes :references :collections])) - ;(map (get-in model [:classes class-kw]) [:references :collections]) - ) + (apply merge (map (get-in model [:classes class-kw]) [:attributes :references :collections]))) (defn referenced-type "Given a model, a class, and a collection or reference, return the class of the collection or reference. @@ -28,8 +25,8 @@ => :Gene" [model field-kw class-kw] ;(.log js/console "referenced-type given" field-kw class-kw) - ;(.log js/console "which produces" (keyword (:referencedType (get (relationships model class-kw) field-kw)))) - (keyword (:referencedType (get (relationships model class-kw) field-kw)))) + ;(.log js/console "which produces" (keyword (:referencedType (get (properties model class-kw) field-kw)))) + (keyword (:referencedType (get (properties model class-kw) field-kw)))) (defn referenced-class "Given a model, a reference/collection, and a class, @@ -51,7 +48,7 @@ (referenced-class im-model :Gene :homologues) => :Gene" [model field-kw class-kw] - (get (relationships model class-kw) field-kw)) + (get (properties model class-kw) field-kw)) (defn class-value "Given a model and a field, return that field from the data model. @@ -108,6 +105,18 @@ (let [l (last (take-while #(does-not-contain? % :type) (walk model path)))] (keyword (or (:referencedType l) (keyword (:name l)))))) + +(defn relationships + "Returns all relationships (references and collections) for a given string path." + [model path] + (apply merge (map (get-in model [:classes (class model path)]) [:references :collections]))) + +(defn attributes + "Returns all attributes for a given string path." + [model path] + (apply merge (map (get-in model [:classes (class model path)]) [:attributes]))) + + (defn class? "Returns true if path is a class. (class im-model `Gene.diseases`) @@ -133,4 +142,5 @@ (fn [total next] (str total (if total " > ") (or (:displayName next) (:name next)))) nil - (if exclude-root? (rest (walk model path)) (walk model path))))) \ No newline at end of file + (if exclude-root? (rest (walk model path)) (walk model path))))) + From 83f8104fa8bc68fa53fc6662ea433b6df600b21e Mon Sep 17 00:00:00 2001 From: Joshua Heimbach Date: Thu, 23 Feb 2017 11:01:25 +0000 Subject: [PATCH 18/22] Add subclasses fn to imcljs/path --- src/imcljs/core.cljs | 16 +++++++++++++++- src/imcljs/internal/io.cljs | 8 ++++---- src/imcljs/path.cljs | 12 ++++++++++++ 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/imcljs/core.cljs b/src/imcljs/core.cljs index fbc64a7..bc7c881 100644 --- a/src/imcljs/core.cljs +++ b/src/imcljs/core.cljs @@ -10,4 +10,18 @@ (enable-console-print!) -(defn on-js-reload []) +(def service {:root "beta.flymine.org/beta" + :model {:name "genomic"}}) + +(defn on-js-reload [] + + + (go (let [model (> model + :classes + (filter (fn [[_ properties]] (one-of? (:extends properties) (name path-class)))) + (map first) + not-empty))) From 6b596fa22db513d88dc05edfb5aa3de62cd160ea Mon Sep 17 00:00:00 2001 From: Joshua Heimbach Date: Wed, 1 Mar 2017 12:26:16 +0000 Subject: [PATCH 19/22] Format whitespace when converting query to XML string --- src/imcljs/core.cljs | 9 ++------- src/imcljs/query.cljs | 4 ++-- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/imcljs/core.cljs b/src/imcljs/core.cljs index bc7c881..338ef65 100644 --- a/src/imcljs/core.cljs +++ b/src/imcljs/core.cljs @@ -14,13 +14,8 @@ :model {:name "genomic"}}) (defn on-js-reload [] - - - (go (let [model (" (apply str (map (partial map->xmlstr "constraint") (:where query))) - ""))) + "\n"))) (defn deconstruct-by-class "Deconstructs a query by its views and groups them by class. From 9a0fdfd34c136e56283e9bd5d9a0cd997779aede Mon Sep 17 00:00:00 2001 From: Joshua Heimbach Date: Thu, 2 Mar 2017 16:18:03 +0000 Subject: [PATCH 20/22] Add unique-values function for fetching unique values of a path within a query (different from posible-alues) --- src/imcljs/core.cljs | 6 +++++- src/imcljs/fetch.cljs | 16 +++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/imcljs/core.cljs b/src/imcljs/core.cljs index 338ef65..f5014df 100644 --- a/src/imcljs/core.cljs +++ b/src/imcljs/core.cljs @@ -13,9 +13,13 @@ (def service {:root "beta.flymine.org/beta" :model {:name "genomic"}}) +(def query {:from "Gene" :select ["Gene.organism.name"]}) + (defn on-js-reload [] (go - (let [model (! chan]])) ; Quicksearch @@ -30,6 +32,18 @@ [service path & [options]] (restful :get "/path/values" service (merge {:path path :format "json"} options))) +(defn unique-values + "Fetches unique values for a path within a query. Providing a limit shortcircuits the request + and returns false if the unique values exceed the limit" + [service query path & [limit]] + (let [return-chan (chan)] + (go + (let [{unique-count :uniqueValues} (! return-chan (! return-chan false)))) + return-chan)) + ; Assets (defn lists From 3b5020187ca897695a34b0cb841445a74552fa09 Mon Sep 17 00:00:00 2001 From: Joshua Heimbach Date: Wed, 8 Mar 2017 14:01:01 +0000 Subject: [PATCH 21/22] Add function to adjust path to its last class and any attribute --- src/imcljs/core.cljs | 6 +++--- src/imcljs/path.cljs | 11 +++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/imcljs/core.cljs b/src/imcljs/core.cljs index f5014df..cf06f3c 100644 --- a/src/imcljs/core.cljs +++ b/src/imcljs/core.cljs @@ -6,7 +6,8 @@ [imcljs.path :as path] [imcljs.query :as query] [imcljs.save :as save] - [imcljs.entity :as entity])) + [imcljs.entity :as entity] + [imcljs.logic :as logic])) (enable-console-print!) @@ -18,8 +19,7 @@ (defn on-js-reload [] (go (let [model ( Organism.name" + [model path] + (let [attribute? (not (class? model path)) + walked (reverse (walk model path))] + (if attribute? + (str (:name (nth walked 1)) "." (:name (nth walked 0))) + (str (:name (nth walked 0)))))) + (defn friendly "Returns a path as a strong" ([model path & [exclude-root?]] From 7defc7186ac1e8a04391e798f208d0c6d79bacde Mon Sep 17 00:00:00 2001 From: Joshua Heimbach Date: Wed, 8 Mar 2017 14:10:17 +0000 Subject: [PATCH 22/22] Remove logic ns require (does not exist yet) --- src/imcljs/core.cljs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/imcljs/core.cljs b/src/imcljs/core.cljs index cf06f3c..f8ecf42 100644 --- a/src/imcljs/core.cljs +++ b/src/imcljs/core.cljs @@ -6,8 +6,7 @@ [imcljs.path :as path] [imcljs.query :as query] [imcljs.save :as save] - [imcljs.entity :as entity] - [imcljs.logic :as logic])) + [imcljs.entity :as entity])) (enable-console-print!)