Skip to content

Feature/new fluree vocabulary #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions resources/contexts/fluree/v1.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{:protected true
"ledger" {:id "https://ns.flur.ee/ledger#ledger"}
"defaultContext" {:type :json :id "https://ns.flur.ee/ledger#defaultContext" }
"delete" {:type :json :id "https://ns.flur.ee/ledger#delete"}
"insert" {:type :json :id "https://ns.flur.ee/ledger#insert"}
"opts" {:type :json :id "https://ns.flur.ee/ledger#opts"}
"where" {:type :json :id "https://ns.flur.ee/ledger#where"}
"values" {:type :json :id "https://ns.flur.ee/ledger#values"}}
30 changes: 30 additions & 0 deletions resources/contexts/fluree/v1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"@context": {
"@protected": true,
"ledger": {"@id": "https://ns.flur.ee/ledger#ledger"},
"defaultContext": {
"@type": "@json",
"@id": "https://ns.flur.ee/ledger#defaultContext"
},
"where": {
"@type": "@json",
"@id": "https://ns.flur.ee/ledger#where"
},
"values": {
"@type": "@json",
"@id": "https://ns.flur.ee/ledger#values"
},
"delete": {
"@type": "@json",
"@id": "https://ns.flur.ee/ledger#delete"
},
"insert": {
"@type": "@json",
"@id": "https://ns.flur.ee/ledger#insert"
},
"opts": {
"@type": "@json",
"@id": "https://ns.flur.ee/ledger#opts"
}
}
}
6 changes: 5 additions & 1 deletion src/fluree/json_ld/impl/external.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@
"https://w3id.org/openbadges#" "org.w3id.openbadges.edn"
"https://purl.imsglobal.org/spec/clr/vocab#" "org.imsglobal.spec.clr.vocab.edn"})

(def context->file {"https://ns.flur.ee/ledger/v1"
(def context->file {"https://ns.flur.ee"
{:source "contexts/fluree/v1.json"
:parsed "contexts/fluree/v1.edn"}

"https://ns.flur.ee/ledger/v1"
{:source "contexts/fluree/ledger/v1.jsonld"
:parsed "contexts/fluree/ledger/v1.edn"}

Expand Down
109 changes: 69 additions & 40 deletions src/fluree/json_ld/processor/api.clj
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
(parsed [x]))

(extend-protocol Parseable
jakarta.json.EmptyArray
(parsed [x] [])
;; JsonArray
org.glassfish.json.JsonArrayBuilderImpl$JsonArrayImpl
(parsed [x]
Expand Down Expand Up @@ -50,39 +52,62 @@
(StringReader.)
(JsonDocument/of)))

(defrecord StaticLoader []
(defn ->document
"Takes a document-loader, which takes a url and options and returns a json string
context document (must have an \"@context\" key with a context as its value).

document-loader: [url options] => json-string
"
[document-loader url options]
(let [url-string (.toString ^URI url)]
(try
(let [json-string (document-loader url-string options)]
(JsonDocument/of (io/input-stream (.getBytes ^String json-string))))
(catch Exception e
(throw (JsonLdError. JsonLdErrorCode/LOADING_REMOTE_CONTEXT_FAILED
(str "Unable to load context: " url-string)))))))

(defrecord PluggableLoader [document-loader]
DocumentLoader
(loadDocument [_ url options]
(if-let [{path :source} (external/context->file (.toString url))]
(-> (FileLoader.)
(.loadDocument (.toURI (io/resource path))
(DocumentLoaderOptions.)))
(throw (JsonLdError. JsonLdErrorCode/LOADING_REMOTE_CONTEXT_FAILED
(str "Unable to load static context: " (.toString url)))))))
(->document document-loader url options)))

(defn static-loader
[url options]
(if-let [{path :source} (external/context->file url)]
(slurp (io/resource path))
(throw (ex-info (str "Unable to load static context: " url)
{:url url}))))

(defn expand
[json-ld]
(-> (->json-document json-ld)
(JsonLd/expand)
(.loader ^DocumentLoader (->StaticLoader))
(.get)
(parsed)))
([json-ld]
(expand json-ld {:document-loader static-loader}))
([json-ld opts]
(-> (->json-document json-ld)
(JsonLd/expand)
(.loader ^DocumentLoader (->PluggableLoader (:document-loader opts)))
(.get)
(parsed))))

(defn compact
[json-ld context]
(-> (->json-document json-ld)
(JsonLd/compact (->json-document context))
(.loader ^DocumentLoader (->StaticLoader))
(.get)
(parsed)))
([json-ld context]
(compact json-ld context {:document-loader static-loader}))
([json-ld context opts]
(-> (->json-document json-ld)
(JsonLd/compact (->json-document context))
(.loader ^DocumentLoader (->PluggableLoader (:document-loader opts)))
(.get)
(parsed))))

(defn flatten
[json-ld]
(-> (->json-document json-ld)
(JsonLd/flatten)
(.loader ^DocumentLoader (->StaticLoader))
(.get)
(parsed)))
([json-ld]
(flatten json-ld {:document-loader static-loader}))
([json-ld opts]
(-> (->json-document json-ld)
(JsonLd/flatten)
(.loader ^DocumentLoader (->PluggableLoader (:document-loader opts)))
(.get)
(parsed))))

(defn- ->statement
[^RdfNQuad quad]
Expand Down Expand Up @@ -114,23 +139,27 @@
" ."))

(defn to-rdf
[json-ld]
(-> (->json-document json-ld)
(JsonLd/toRdf)
(.loader ^DocumentLoader (->StaticLoader))
(.get)
(.toList)
(->> (reduce (fn [doc quad] (str doc (->statement quad) "\n")) ""))))
([json-ld]
(to-rdf json-ld {:document-loader static-loader}))
([json-ld opts]
(-> (->json-document json-ld)
(JsonLd/toRdf)
(.loader ^DocumentLoader (->PluggableLoader (:document-loader opts)))
(.get)
(.toList)
(->> (reduce (fn [doc quad] (str doc (->statement quad) "\n")) "")))))

(defn canonize
[json-ld]
(-> (->json-document json-ld)
(JsonLd/toRdf)
(.loader ^DocumentLoader (->StaticLoader))
(.get)
(RdfNormalize/normalize)
(.toList)
(->> (reduce (fn [doc quad] (str doc (->statement quad) "\n")) ""))))
([json-ld]
(canonize json-ld {:document-loader static-loader}))
([json-ld opts]
(-> (->json-document json-ld)
(JsonLd/toRdf)
(.loader ^DocumentLoader (->PluggableLoader (:document-loader opts)))
(.get)
(RdfNormalize/normalize)
(.toList)
(->> (reduce (fn [doc quad] (str doc (->statement quad) "\n")) "")))))

(comment
;; These work up to translating the resulting json-ld back into edn
Expand Down
99 changes: 62 additions & 37 deletions src/fluree/json_ld/processor/api.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -3,54 +3,79 @@
(:require ["jsonld" :as jldjs]
[fluree.json-ld.impl.external :as external]))

(defn pluggable-loader
"Takes a document-loader, which takes a url and options and returns a json string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this missing a conclusion or a comma? In other words, does "and returns a json string..." apply to the document-loader (in which case this is missing a conclusion about what the fn itself returns / does) or to the fn itself (in which case this is missing a comma between "and options" and "and returns" (or you could wrap "which takes a url and options" in parens).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see how that's confusing! I tried rewriting it a few times and then decided to just document the argument explicitly, I think it's an improvement.

context document (must have an \"@context\" key with a context as its value).

document-loader: [url options] => json-string
"
[document-loader]
(fn [url options]
(js/Promise.
(fn [resolve reject]
(try
(let [json-string (document-loader url options)]
(resolve #js{"contextUrl" nil, "document" json-string, "documentUrl" url}))
(catch js/Error e
(reject (throw #js{"name" "jsonld.LoadDocumentError"
"message" (str "Unable to load static context: " url)
"details" {"code" "loading remote context failed"
"url" url}}))))))))

(defn static-loader
[url options]
(js/Promise.
(fn [resolve reject]
(if-let [context (get external/inlined-contexts url)]
(resolve #js{"contextUrl" nil, "document" context, "documentUrl" url})
(reject (throw #js{"name" "jsonld.LoadDocumentError"
"message" (str "Unable to load static context: " url)
"details" {"code" "loading remote context failed"
"url" url}}))))))
(get external/inlined-contexts url))

(defn compact
[json-ld context]
(-> json-ld
(clj->js)
(jldjs/compact (clj->js context) #js{"documentLoader" static-loader})
(.then (fn [result] (js->clj result)))))
([json-ld context]
(compact json-ld context {:document-loader static-loader}))
([json-ld context opts]
(-> json-ld
(clj->js)
(jldjs/compact (clj->js context) #js{"documentLoader" (pluggable-loader (:document-loader opts))})
(.then (fn [result] (js->clj result))))))

(defn expand
[json-ld]
(-> json-ld
(clj->js)
(jldjs/expand #js{"documentLoader" static-loader})
(.then (fn [result] (js->clj result)))))
([json-ld]
(expand json-ld {:document-loader static-loader}))
([json-ld opts]
(-> json-ld
(clj->js)
(jldjs/expand #js{"documentLoader" (pluggable-loader (:document-loader opts))})
(.then (fn [result] (js->clj result))))))

(defn flatten
[json-ld]
(-> json-ld
(clj->js)
(jldjs/flatten #js{"documentLoader" static-loader})
(.then (fn [result] (js->clj result)))))
([json-ld]
(flatten json-ld {:document-loader static-loader}))
([json-ld opts]
(-> json-ld
(clj->js)
(jldjs/flatten #js{"documentLoader" (pluggable-loader (:document-loader opts))})
(.then (fn [result] (js->clj result))))))

(defn from-rdf
[n-quads]
(-> n-quads
(clj->js)
(jldjs/fromRDF #js{"format" "application/n-quads" "documentLoader" static-loader})
(.then (fn [result] (js->clj result)))))
([n-quads]
(from-rdf n-quads {:document-loader static-loader}))
([n-quads opts]
(-> n-quads
(clj->js)
(jldjs/fromRDF #js{"format" "application/n-quads"
"documentLoader" (pluggable-loader (:document-loader opts))})
(.then (fn [result] (js->clj result))))))

(defn to-rdf
[json-ld]
(-> json-ld
(clj->js)
(jldjs/expand #js{"documentLoader" static-loader})
(.then (fn [expanded] (jldjs/toRDF expanded #js{"format" "application/n-quads"})))))
([json-ld]
(to-rdf json-ld {:document-loader static-loader}))
([json-ld opts]
(-> json-ld
(clj->js)
(jldjs/expand #js{"documentLoader" (pluggable-loader (:document-loader opts))})
(.then (fn [expanded] (jldjs/toRDF expanded #js{"format" "application/n-quads"}))))))

(defn canonize
[json-ld]
(-> (to-rdf json-ld)
(.then (fn [rdf]
(jldjs/canonize rdf #js {"algorithm" "URDNA2015" "inputFormat" "application/n-quads"})))))
([json-ld]
(canonize json-ld {:document-loader static-loader}))
([json-ld opts]
(-> (to-rdf json-ld opts)
(.then (fn [rdf]
(jldjs/canonize rdf #js {"algorithm" "URDNA2015" "inputFormat" "application/n-quads"}))))))
30 changes: 23 additions & 7 deletions test/fluree/json_ld/processor/api_test.clj
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
(ns fluree.json-ld.processor.api-test
(:require [fluree.json-ld.processor.api :as jld-processor]
[clojure.test :as t :refer [deftest is testing]]
[clojure.string :as str]))
[clojure.string :as str]
[jsonista.core :as json]))

(def context {"@version" 1.1,
"address" "fluree:address",
Expand Down Expand Up @@ -41,15 +42,30 @@
(is (= expanded
result))))

(testing "static context"
(is (= expanded
(jld-processor/expand (assoc commit "@context"
["https://ns.flur.ee/ledger/v1"
{"cool" {"@id" "fluree:cool" "@type" "xsd:boolean"}}]))))

(is (= "Unable to load context: http://failure.foo"
(try (jld-processor/expand (assoc commit "@context" "http://failure.foo"))
(catch Exception e
(:cause (Throwable->map e)))))))

(testing "remote context"
(let [result (jld-processor/expand (assoc commit "@context"
[ "https://ns.flur.ee/ledger/v1"
{"cool" {"@id" "fluree:cool" "@type" "xsd:boolean"}}]))]
(is (= expanded
result))))
(let [test-docloader (fn [_ _] (json/write-value-as-string {"@context" {"foo" "http://example.com/foo#"}}))]
(is (= [{"http://example.com/foo#bar" [{"@value" 1}]}]
(jld-processor/expand {"@context" "foo:context" "foo:bar" 1}
{:document-loader test-docloader})))
(is (= "Unable to load context: foo:context"
(try (jld-processor/expand {"@context" "foo:context" "foo:bar" 1}
{:document-loader (fn [_ _] (throw (ex-info "borken loader" {})))})
(catch Exception e
(:cause (Throwable->map e))))))))

(testing "remote context failure"
(is (= "Unable to load static context: http://failure.foo"
(is (= "Unable to load context: http://failure.foo"
(try (jld-processor/expand (assoc commit "@context" "http://failure.foo"))
(catch Exception e
(:cause (Throwable->map e))))))))
Expand Down
Loading