diff --git a/src/fluree/db/api.cljc b/src/fluree/db/api.cljc index 9e827dbfdf..e64bf6348a 100644 --- a/src/fluree/db/api.cljc +++ b/src/fluree/db/api.cljc @@ -18,6 +18,7 @@ [fluree.db.transact :as transact] [fluree.db.util :as util] [fluree.db.util.async :refer [go-try parsed-txn :opts syntax/coerce-ledger-opts) + _ (util.ledger/validate-ledger-name ledger-id) ledger (async-db ->AsyncDB deliver!) -(defrecord AsyncDB [alias branch commit t db-chan] +(defrecord AsyncDB [alias commit t db-chan] dbproto/IFlureeDb (-query [_ tracker query-map] (go-try @@ -33,7 +33,7 @@ (async-db alias branch commit* t)] + updated-db (->async-db alias commit* t)] (go-try (let [db (AsyncDB alias branch commit t db-chan-at-t)] + db-at-t (->AsyncDB alias commit t db-chan-at-t)] (go (try* (let [db (AsyncDB alias branch commit t root-ch)] + root-db (->AsyncDB alias commit t root-ch)] (go (try* (let [db (AsyncDB ledger-alias branch commit-map t (async/promise-chan))) + [ledger-alias commit-map t] + (->AsyncDB ledger-alias commit-map t (async/promise-chan))) (defn load - ([ledger-alias branch commit-catalog index-catalog commit-jsonld indexing-opts] + ([ledger-alias commit-catalog index-catalog commit-jsonld indexing-opts] (let [commit-map (commit-data/jsonld->clj commit-jsonld)] - (load ledger-alias branch commit-catalog index-catalog commit-jsonld commit-map indexing-opts))) - ([ledger-alias branch commit-catalog index-catalog commit-jsonld commit-map indexing-opts] + (load ledger-alias commit-catalog index-catalog commit-jsonld commit-map indexing-opts))) + ([ledger-alias commit-catalog index-catalog commit-jsonld commit-map indexing-opts] (let [t (-> commit-map :data :t) - ;; Ensure AsyncDB commit reflects index t when an index address exists but :t is missing - commit-map* (if (and (get-in commit-map [:index :address]) - (nil? (get-in commit-map [:index :data :t]))) - (assoc-in commit-map [:index :data :t] t) - commit-map) - async-db (->async-db ledger-alias branch commit-map* t)] + async-db (->async-db ledger-alias commit-map t)] (go - (let [db ( commit-map commit-data/->json-ld json-ld/expand)) (defn load-db - [alias branch commit-catalog index-catalog commit-map] + [alias commit-catalog index-catalog commit-map] (let [commit-jsonld (commit-map->commit-jsonld commit-map)] - (async-db/load alias branch commit-catalog index-catalog + (async-db/load alias commit-catalog index-catalog commit-jsonld commit-map nil))) (defn update-index-async @@ -56,11 +56,11 @@ return immediately - and for a large amount of novelty, updating the db to reflect the latest index can take some time which would lead to atom contention." - [{:keys [alias commit branch t] :as current-db} index-map] + [{:keys [alias commit t] :as current-db} index-map] (if (async-db/db? current-db) (dbproto/-index-update current-db index-map) (let [updated-commit (assoc commit :index index-map) - updated-db (async-db/->async-db alias branch updated-commit t)] + updated-db (async-db/->async-db alias updated-commit t)] (go ;; update index in the background, return updated db immediately (->> (dbproto/-index-update current-db index-map) (async-db/deliver! updated-db))) @@ -89,9 +89,9 @@ current-state)))) (defn reload-with-index - [{:keys [commit-catalog index-catalog commit] :as _db} alias branch index] + [{:keys [commit-catalog index-catalog commit alias] :as _db} index] (let [indexed-commit (assoc commit :index index)] - (load-db alias branch commit-catalog index-catalog indexed-commit))) + (load-db alias commit-catalog index-catalog indexed-commit))) (defn use-latest-db "Returns the most recent db from branch-state if it matches @@ -107,22 +107,22 @@ latest-db))) (defn use-latest-index - [{db-commit :commit, :as db} idx-commit alias branch branch-state] + [{db-commit :commit, :as db} idx-commit branch-state] (if (newer-index? idx-commit db-commit) (let [updated-db (or (use-latest-db db idx-commit branch-state) (try* (dbproto/-index-update db (:index idx-commit)) (catch* e (log/error e "Exception updating db with new index, attempting full reload. Exception:" (ex-message e)) - (reload-with-index db alias branch (:index idx-commit)))))] + (reload-with-index db (:index idx-commit)))))] updated-db) db)) (defn index-queue - [alias branch publishers branch-state] + [publishers branch-state] (let [buf (async/sliding-buffer 1) queue (async/chan buf)] (go-loop [last-index-commit nil] (when-let [{:keys [db index-files-ch complete-ch]} (clj commit-jsonld) - initial-db (async-db/load ledger-alias branch-name commit-catalog index-catalog + initial-db (async-db/load alias commit-catalog index-catalog commit-jsonld commit-map indexing-opts) state (atom {:commit commit-map :current-db initial-db}) - idx-q (index-queue ledger-alias branch-name publishers state)] + idx-q (index-queue publishers state)] {:name branch-name - :alias ledger-alias + :alias alias :state state :index-queue idx-q :indexing-opts indexing-opts}))) diff --git a/src/fluree/db/commit/storage.cljc b/src/fluree/db/commit/storage.cljc index 74ac59bf8b..3a74df2e99 100644 --- a/src/fluree/db/commit/storage.cljc +++ b/src/fluree/db/commit/storage.cljc @@ -7,6 +7,7 @@ [fluree.db.util :as util :refer [get-first get-first-id get-first-value try* catch*]] [fluree.db.util.async :refer [ genesis-commit (get "data") (assoc "@context" initial-context)) - {db-address :address} ( genesis-commit* (assoc "address" commit-address) json-ld/expand)))) diff --git a/src/fluree/db/connection.cljc b/src/fluree/db/connection.cljc index e056863ef8..bfc2b1a45f 100644 --- a/src/fluree/db/connection.cljc +++ b/src/fluree/db/connection.cljc @@ -68,6 +68,14 @@ (->Connection id state parallelism commit-catalog index-catalog primary-publisher secondary-publishers remote-systems serializer cache defaults))) +(defn normalize-ledger-alias + "Ensures ledger alias includes branch. + If no : symbol present, appends :main as default branch." + [ledger-alias] + (if (clojure.string/includes? ledger-alias ":") + ledger-alias + (str ledger-alias ":" commit-data/default-branch))) + (defn register-ledger "Creates a promise-chan and saves it in a cache of ledgers being held in-memory on the conn. @@ -165,7 +173,9 @@ "From a connection, lookup primary address from nameservice(s) for a given ledger alias" [{:keys [primary-publisher] :as _conn} ledger-alias] - (nameservice/publishing-address primary-publisher ledger-alias)) + (->> ledger-alias + normalize-ledger-alias + (nameservice/publishing-address primary-publisher))) (defn lookup-commit* "Returns commit address from first matching nameservice on a conn @@ -216,6 +226,7 @@ (defn published-ledger? [conn ledger-alias] (go-try + (log/debug "published-ledger? checking for:" ledger-alias) (loop [[nsv & r] (publishers conn)] (if nsv (or ( conn :defaults :identity))) (defn parse-ledger-options - [conn {:keys [did branch indexing] - :or {branch commit-data/default-branch}}] + [conn {:keys [did indexing]}] (let [did* (parse-identity conn did) ledger-default (-> conn :defaults :indexing) indexing* (merge ledger-default indexing)] {:did did* - :branch branch :indexing indexing*})) (defn throw-ledger-exists @@ -290,26 +280,28 @@ (defn create-ledger [{:keys [commit-catalog index-catalog primary-publisher secondary-publishers] :as conn} ledger-alias opts] (go-try - (if (ledger-alias "Returns ledger alias from commit map, if present. If not present @@ -320,12 +312,6 @@ (some (fn [ns] (nameservice/alias ns db-alias)))))) -(defn throw-missing-branch - [address ledger-alias] - (throw (ex-info (str "No committed branches exist for ledger: " ledger-alias - " at address: " address) - {:status 400, :error :db/missing-branch}))) - (defn load-ledger* [{:keys [commit-catalog index-catalog primary-publisher secondary-publishers] :as conn} ledger-chan address] @@ -341,14 +327,10 @@ commit-address index-address)) expanded-commit (json-ld/expand commit) - ledger-alias (commit->ledger-alias conn address expanded-commit) - ;; Determine branch using helpers in priority order - branch (or (branch-from-commit expanded-commit) - (branch-from-ns ns-record) - (branch-from-alias ledger-alias)) - - {:keys [did branch indexing]} (parse-ledger-options conn {:branch branch}) - ledger (ledger/instantiate ledger-alias address branch commit-catalog index-catalog + ledger-alias (commit->ledger-alias conn address expanded-commit) + + {:keys [did indexing]} (parse-ledger-options conn {}) + ledger (ledger/instantiate ledger-alias address commit-catalog index-catalog primary-publisher secondary-publishers indexing did expanded-commit)] (ns-subscribe/subscribe-ledger conn ledger-alias) (async/put! ledger-chan ledger) @@ -374,18 +356,22 @@ (defn load-ledger-alias [conn alias] (go-try - (let [[cached? ledger-chan] (register-ledger conn alias)] + (let [;; Normalize ledger-alias to include branch + normalized-alias (normalize-ledger-alias alias) + [cached? ledger-chan] (register-ledger conn normalized-alias)] (if cached? ( jsonld (get-first-value const/iri-address) not-empty) @@ -159,7 +158,6 @@ (cond-> {:id id :v v :alias alias - :branch branch :time time :tag (mapv get-value tags) :data (parse-db-data data) @@ -223,12 +221,9 @@ (defn blank-commit "Creates a skeleton blank commit map." - [alias branch publish-addresses init-time] + [alias publish-addresses init-time] (let [commit-json (->json-ld {:alias alias - :v 0 - :branch (if branch - (util/keyword->str branch) - default-branch) + :v commit-version :data {:t 0 :flakes 0 :size 0} @@ -416,7 +411,7 @@ db-sid. Used when committing to an in-memory ledger value and when reifying a ledger from storage on load." [db t commit] - (let [{:keys [id address alias branch data time v previous author issuer message txn]} commit + (let [{:keys [id address alias data time v previous author issuer message txn]} commit {db-t :t, db-address :address, data-id :id, :keys [flakes size]} data commit-sid (iri/encode-iri db id) db-sid (iri/encode-iri db data-id)] @@ -426,8 +421,6 @@ (flake/create commit-sid const/$_address address const/$xsd:string t true nil) ;; alias (flake/create commit-sid const/$_ledger:alias alias const/$xsd:string t true nil) - ;; branch - (flake/create commit-sid const/$_ledger:branch branch const/$xsd:string t true nil) ;; v (flake/create commit-sid const/$_v v const/$xsd:int t true nil) ;; time diff --git a/src/fluree/db/flake/flake_db.cljc b/src/fluree/db/flake/flake_db.cljc index 0c2edd1169..d182c4a26a 100644 --- a/src/fluree/db/flake/flake_db.cljc +++ b/src/fluree/db/flake/flake_db.cljc @@ -290,7 +290,7 @@ (merge-flakes t-new all-flakes) (assoc :commit commit-metadata))))) -(defrecord FlakeDB [index-catalog commit-catalog alias branch commit t tt-id stats +(defrecord FlakeDB [index-catalog commit-catalog alias commit t tt-id stats spot post opst tspo vg schema comparators staged novelty policy namespaces namespace-codes max-namespace-code reindex-min-bytes reindex-max-bytes max-old-indexes] @@ -410,7 +410,7 @@ (defn display [db] - (select-keys db [:alias :branch :t :stats :policy])) + (select-keys db [:alias :t :stats :policy])) #?(:cljs (extend-type FlakeDB IPrintWithWriter @@ -535,9 +535,9 @@ ;; TODO - VG - need to reify vg from db-root!! (defn load - ([ledger-alias commit-catalog index-catalog branch commit-pair] - (load ledger-alias commit-catalog index-catalog branch commit-pair {})) - ([ledger-alias commit-catalog index-catalog branch [commit-jsonld commit-map] indexing-opts] + ([ledger-alias commit-catalog index-catalog commit-pair] + (load ledger-alias commit-catalog index-catalog commit-pair {})) + ([ledger-alias commit-catalog index-catalog [commit-jsonld commit-map] indexing-opts] (go-try (let [commit-t (-> commit-jsonld (get-first const/iri-data) @@ -546,21 +546,12 @@ ( root-map :namespace-codes iri/get-max-namespace-code) - ;; Ensure commit map reflects loaded index t when an index address exists - commit-map* (if (get-in commit-map [:index :address]) - (update commit-map :index - (fn [idx] - (let [existing-data (:data idx) - updated-data (assoc (or existing-data {}) :t (:t root-map))] - (assoc idx :data updated-data)))) - commit-map) indexed-db (-> root-map (add-reindex-thresholds indexing-opts) (assoc :index-catalog index-catalog :commit-catalog commit-catalog :alias ledger-alias - :branch branch - :commit commit-map* + :commit commit-map :tt-id nil :comparators index/comparators :staged nil diff --git a/src/fluree/db/flake/index/novelty.cljc b/src/fluree/db/flake/index/novelty.cljc index 6b4ed6db0d..20baacc8e9 100644 --- a/src/fluree/db/flake/index/novelty.cljc +++ b/src/fluree/db/flake/index/novelty.cljc @@ -391,13 +391,13 @@ refresh-ch ([{:keys [garbage], refreshed-db :db, :as _status}] - (let [{:keys [index-catalog alias branch] :as refreshed-db*} + (let [{:keys [index-catalog alias] :as refreshed-db*} (assoc-in refreshed-db [:stats :indexed] t) ;; TODO - ideally issue garbage/root writes to RAFT together ;; as a tx, currently requires waiting for both ;; through raft sync garbage-res (when (seq garbage) - (let [write-res (Ledger {:id (random-uuid) :did did :state (atom (initial-state branches branch)) - :alias ledger-alias + :alias alias ;; Full alias including branch :address ledger-address :commit-catalog commit-catalog :index-catalog index-catalog @@ -147,33 +149,24 @@ :reasoner #{} :indexing-opts indexing-opts}))) -(defn normalize-alias - "For a ledger alias, removes any preceding '/' or '#' if exists." - [ledger-alias] - (if (or (str/starts-with? ledger-alias "/") - (str/starts-with? ledger-alias "#")) - (subs ledger-alias 1) - ledger-alias)) - (defn create "Creates a new ledger, optionally bootstraps it as permissioned or with default context." [{:keys [alias primary-address publish-addresses commit-catalog index-catalog primary-publisher secondary-publishers]} - {:keys [did branch indexing] :as _opts}] + {:keys [did indexing] :as _opts}] (go-try - (let [ledger-alias* (normalize-alias alias) - ;; internal-only opt used for migrating ledgers without genesis commits + (let [;; internal-only opt used for migrating ledgers without genesis commits init-time (util/current-time-iso) genesis-commit (map genesis-commit nil) compact-commit (commit-data/->json-ld commit-map)] (nested checks are independent) + + SAFETY: + - Read-only detection phase before any modifications + - Sequential processing with proper error handling + - Old files only deleted after successful migration + - Logging for monitoring and debugging" + (:require #?(:clj [clojure.java.io :as io]) + #?@(:cljs [[fluree.db.platform :as platform] + ["fs" :as node-fs] + ["path" :as node-path]]) + [clojure.string :as str] + [fluree.db.constants :as const] + [fluree.db.nameservice.storage :as ns-storage] + [fluree.db.storage :as storage] + [fluree.db.util.async :refer [> (file-seq root-file) + (filter #(.isFile ^java.io.File %)) + (map #(.getPath ^java.io.File %)) + (filter #(and (str/ends-with? % ".json") + (not (str/includes? % "/ns@v1/")) + (not (str/includes? % "/commit/")) + (not (str/includes? % "/index/")) + (not (str/includes? % "/txn/")))))) + :cljs + (if platform/BROWSER + (throw (ex-info "Migration not supported in browser" {:path root-path})) + ;; Node.js implementation + (let [find-files (fn find-files [dir acc] + (let [entries (node-fs/readdirSync dir #js {:withFileTypes true})] + (reduce (fn [acc entry] + (let [entry-name (.-name entry) + full-path (node-path/join dir entry-name)] + (cond + (.isDirectory entry) + (if (not (contains? #{"ns@v1" "commit" "index" "txn"} entry-name)) + (find-files full-path acc) + acc) + + (and (.isFile entry) + (str/ends-with? entry-name ".json")) + (conj acc full-path) + + :else acc))) + acc + (js->clj entries))))] + (find-files root-path []))))) + +(defn find-old-nameservice-files + "Find old nameservice files in ledger directories - handles both root level and nested paths" + [file-store] + (go-try + (let [root-path (:root file-store) + ;; Find all .json files recursively, excluding ns@v1 and commit directories + all-json-files (find-json-files-recursively root-path) + ;; Filter to only nameservice files (those that match ledger naming pattern) + ;; clj-kondo false positive - ledger-path is used in the clj branch + ns-files + (filter (fn [path] + (let [relative-path (str/replace path (str root-path "/") "") + ;; Remove .json extension + ledger-path (str/replace relative-path #"\.json$" "") + ledger-full-path (str root-path "/" ledger-path)] + ;; Check if corresponding ledger directory exists + #?(:clj (.exists (io/file ledger-full-path)) + :cljs (if platform/BROWSER + false + (node-fs/existsSync ledger-full-path))))) + all-json-files)] + (mapv (fn [full-path] + (let [relative-path (str/replace full-path (str root-path "/") "") + ledger-alias (str/replace relative-path #"\.json$" "")] + {:ledger-alias ledger-alias + :file-path relative-path + :full-path full-path})) + ns-files)))) + +(defn extract-commit-metadata + "Extract relevant metadata from old nameservice commit for migration" + [old-commit-data] + (let [;; Old format has nested structure: branches[0].commit contains the actual commit data + branches (get old-commit-data "branches") + first-branch (first branches) + commit-data (get first-branch "commit") + ;; Extract values from the nested commit structure + ledger-alias (or (get old-commit-data "ledgerAlias") + (get commit-data "alias")) + branch (or (get commit-data "branch") "main") + commit-address (get commit-data "address") + t-value (get-in commit-data ["data" "t"]) + ;; Extract index address if present in old format + index-address (get-in commit-data ["index" "address"])] + {:ledger-alias ledger-alias + :branch branch + :commit-address commit-address + :t-value t-value + :index-address index-address})) + +(defn migrate-nameservice-file + "Migrate a single pre-ns@v1 nameservice file directly to current nested layout (ns@v2)." + [file-store {:keys [ledger-alias file-path full-path]}] + (go-try + (log/info "Migrating nameservice file for ledger:" ledger-alias) + (when-let [old-data-str ( Nested ns@v1 (ledger/branch.json) migration --- + +(def flat-filename-regex + ;; Explicitly target ns@v1 flat files regardless of current const/ns-version + (re-pattern "^ns@v1/([^/]+)@([^/]+)\\.json$")) + +(defn find-flat-nameservice-files + "Find ns@v1 files using the legacy flat naming: ns@v1/@.json" + [file-store] + (go-try + (if (satisfies? storage/RecursiveListableStore file-store) + (let [paths (" new-path) + ;; If new path already exists, just delete the old file and return + (if ( file-store storage/location (storage/build-address old-path))] + (UTF8 content) + :else content)] + (when-not bytes* + (throw (ex-info (str "Unable to read old nameservice file: " old-path) + {:status 500 :error :db/migration}))) + ( file-store storage/location (storage/build-address old-path))] + ( v2 migration (handles both flat and nested v1 layouts) + +(def v1-flat-regex (re-pattern "^ns@v1/(.+)@([^/]+)\\.json$")) +(def v1-nested-one-regex (re-pattern "^ns@v1/([^/]+)/([^/]+)\\.json$")) +(def v1-nested-two-regex (re-pattern "^ns@v1/([^/]+)/([^/]+)/([^/]+)\\.json$")) + +(defn find-v1-nameservice-files + "Find all ns@v1 nameservice files (flat and nested) and compute target ns@v2 paths. + Scopes discovery to ns@v1 only via recursive listing and avoids scanning root." + [file-store] + (go-try + (if (satisfies? storage/RecursiveListableStore file-store) + (let [paths (> paths + (keep (fn [p] + (cond + (re-matches v1-flat-regex p) + (let [[_ ledger-path branch] (re-matches v1-flat-regex p)] + {:old-path p + :alias (str ledger-path ":" branch) + :new-path (str const/ns-version "/" ledger-path "/" branch ".json")}) + + (re-matches v1-nested-two-regex p) + (let [[_ seg1 seg2 branch] (re-matches v1-nested-two-regex p) + ledger-path (str seg1 "/" seg2)] + {:old-path p + :alias (str ledger-path ":" branch) + :new-path (str const/ns-version "/" ledger-path "/" branch ".json")}) + + (re-matches v1-nested-one-regex p) + (let [[_ ledger branch] (re-matches v1-nested-one-regex p)] + {:old-path p + :alias (str ledger ":" branch) + :new-path (str const/ns-version "/" ledger "/" branch ".json")}) + + :else nil))) + vec)) + []))) + +(defn migrate-v1-file + "Migrate one ns@v1 nameservice file to ns@v2 nested layout. Idempotent if new file exists." + [file-store {:keys [old-path new-path alias]}] + (go-try + (log/info "Migrating ns@v1 record for" alias ":" old-path "->" new-path) + (if ( file-store storage/location (storage/build-address old-path))] + (UTF8 content) + :else content)] + (when-not bytes* + (throw (ex-info (str "Unable to read nameservice file: " old-path) + {:status 500 :error :db/migration}))) + ( file-store storage/location (storage/build-address old-path))] + (" const/ns-version "migration completed. Migrated" + (count (filter :migrated results)) + "files, skipped" (count (filter :skipped results)) "already updated files") + results)))) + [])))) + +(defn run-migration-if-needed + "Run nameservice migrations as needed, minimizing expensive scans. + - If ns@v2 exists: do nothing + - Else if ns@v1 exists: migrate ns@v1 (flat or nested) -> ns@v2 + - Else: if legacy layout likely (has ledgers, no ns@v1/ns@v2), run legacy -> ns@v2" + [file-store] + (go-try + (let [root-path (:root file-store) + v2-path (str (fs/local-path root-path) "/ns@v2") + v1-path (str (fs/local-path root-path) "/ns@v1") + has-ns-v2? (" const/ns-version "...") + (> (file-seq root-file) - (filter #(.isFile ^java.io.File %)) - (map #(.getPath ^java.io.File %)) - (filter #(and (str/ends-with? % ".json") - (not (str/includes? % "/ns@v1/")) - (not (str/includes? % "/commit/")) - (not (str/includes? % "/index/")) - (not (str/includes? % "/txn/")))))) - :cljs - (if platform/BROWSER - (throw (ex-info "Migration not supported in browser" {:path root-path})) - ;; Node.js implementation - (let [find-files (fn find-files [dir acc] - (let [entries (node-fs/readdirSync dir #js {:withFileTypes true})] - (reduce (fn [acc entry] - (let [entry-name (.-name entry) - full-path (node-path/join dir entry-name)] - (cond - (.isDirectory entry) - (if (not (contains? #{"ns@v1" "commit" "index" "txn"} entry-name)) - (find-files full-path acc) - acc) - - (and (.isFile entry) - (str/ends-with? entry-name ".json")) - (conj acc full-path) - - :else acc))) - acc - (js->clj entries))))] - (find-files root-path []))))) - -(defn find-old-nameservice-files - "Find old nameservice files in ledger directories - handles both root level and nested paths" - [file-store] - (go-try - (let [root-path (:root file-store) - ;; Find all .json files recursively, excluding ns@v1 and commit directories - all-json-files (find-json-files-recursively root-path) - ;; Filter to only nameservice files (those that match ledger naming pattern) - ;; clj-kondo false positive - ledger-path is used in the clj branch - ns-files - (filter (fn [path] - (let [relative-path (str/replace path (str root-path "/") "") - ;; Remove .json extension - ledger-path (str/replace relative-path #"\.json$" "") - ledger-full-path (str root-path "/" ledger-path)] - ;; Check if corresponding ledger directory exists - #?(:clj (.exists (io/file ledger-full-path)) - :cljs (if platform/BROWSER - false - (node-fs/existsSync ledger-full-path))))) - all-json-files)] - (mapv (fn [full-path] - (let [relative-path (str/replace full-path (str root-path "/") "") - ledger-alias (str/replace relative-path #"\.json$" "")] - {:ledger-alias ledger-alias - :file-path relative-path - :full-path full-path})) - ns-files)))) - -(defn extract-commit-metadata - "Extract relevant metadata from old nameservice commit for migration" - [old-commit-data] - (let [;; Old format has nested structure: branches[0].commit contains the actual commit data - branches (get old-commit-data "branches") - first-branch (first branches) - commit-data (get first-branch "commit") - ;; Extract values from the nested commit structure - ledger-alias (or (get old-commit-data "ledgerAlias") - (get commit-data "alias")) - branch (or (get commit-data "branch") "main") - commit-address (get commit-data "address") - t-value (get-in commit-data ["data" "t"]) - ;; Extract index address if present in old format - index-address (get-in commit-data ["index" "address"])] - {:ledger-alias ledger-alias - :branch branch - :commit-address commit-address - :t-value t-value - :index-address index-address})) - -(defn migrate-nameservice-file - "Migrate a single old nameservice file to new format" - [file-store {:keys [ledger-alias file-path full-path]}] - (go-try - (log/info "Migrating nameservice file for ledger:" ledger-alias) - (when-let [old-data-str ( store - storage/location - (storage/build-address ledger-alias))) + "Returns the local filename for a ledger's nameservice record. + Expects ledger-alias to be in format 'ledger:branch'. + Returns path like 'ns@v2/ledger-name/branch.json'." + [ledger-alias] + (let [[ledger-name branch] (util.ledger/ledger-parts ledger-alias) + branch (or branch "main")] + (str const/ns-version "/" ledger-name "/" branch ".json"))) (defn ns-record - "Generates nameservice metadata map for JSON storage using new minimal format" - [ledger-alias branch commit-address t index-address] - (let [branch (or branch "main")] + "Generates nameservice metadata map for JSON storage using new minimal format. + Expects ledger-alias to be in format 'ledger:branch'." + [ledger-alias commit-address t index-address] + (let [[alias branch] (util.ledger/ledger-parts ledger-alias) + branch (or branch "main")] (cond-> {"@context" {"f" iri/f-ns} - "@id" (str ledger-alias "@" branch) + "@id" ledger-alias ;; Already includes :branch "@type" ["f:Database" "f:PhysicalDatabase"] - "f:ledger" {"@id" ledger-alias} + "f:ledger" {"@id" alias} ;; Just the ledger name without branch "f:branch" branch "f:commit" {"@id" commit-address} "f:t" t @@ -38,22 +39,14 @@ nameservice/Publisher (publish [_ data] (let [;; Extract data from compact JSON-LD format (both genesis and regular commits now use this) - ledger-alias (get data "alias") - branch (or (get data "branch") - (when (and (string? ledger-alias) - (str/includes? ledger-alias "@")) - (subs ledger-alias (inc (str/last-index-of ledger-alias "@")))) - "main") + ledger-alias (get data "alias") ;; Already includes @branch commit-address (get data "address") t-value (get-in data ["data" "t"]) index-address (get-in data ["index" "address"]) - ns-metadata (ns-record ledger-alias branch commit-address t-value index-address) + ns-metadata (ns-record ledger-alias commit-address t-value index-address) record-bytes (json/stringify-UTF8 ns-metadata) - filename (local-filename ledger-alias branch)] - (log/debug "nameservice.storage/publish start" {:ledger ledger-alias :branch branch :filename filename}) - (let [res (storage/write-bytes store filename record-bytes)] - (log/debug "nameservice.storage/publish enqueued" {:ledger ledger-alias :branch branch :filename filename}) - res))) + filename (local-filename ledger-alias)] + (storage/write-bytes store filename record-bytes))) (retract [_ ledger-alias] (let [filename (local-filename ledger-alias) @@ -63,14 +56,16 @@ (storage/delete store address))) (publishing-address [_ ledger-alias] - (go (publishing-address* store ledger-alias))) + ;; Just return the alias - lookup will handle branch extraction via local-filename + (go ledger-alias)) nameservice/iNameService (lookup [_ ledger-address] (go-try - (let [{:keys [alias branch]} (nameservice/resolve-address (storage/location store) ledger-address nil) - branch (or branch "main") - filename (local-filename alias branch)] + ;; ledger-address is just the alias (potentially with @branch) + (let [filename (local-filename ledger-address)] + (log/debug "StorageNameService lookup:" {:ledger-address ledger-address + :filename filename}) (when-let [record-bytes (jsonld staged-db commit-data-opts) {:keys [txn-id author annotation]} - (db-id (:hash data-write-result)) keypair {:did did, :private private} @@ -268,7 +271,7 @@ _ (log/debug "commit!: write-commit start" {:ledger ledger-alias}) {:keys [commit-map commit-jsonld write-result]} - ( 'my-ledger'" + [ledger-alias] + (first (str/split ledger-alias #":" 2))) + +(defn ledger-branch + "Extracts the branch name from a ledger alias. + Returns the branch name or nil if no branch is specified. + e.g., 'my-ledger:main' -> 'main' + 'my-ledger' -> nil" + [ledger-alias] + (second (str/split ledger-alias #":" 2))) + +(defn ledger-parts + "Splits a ledger alias into [ledger-name branch-name]. + e.g., 'my-ledger:main' -> ['my-ledger' 'main'] + 'my-ledger' -> ['my-ledger' nil]" + [ledger-alias] + (let [parts (str/split ledger-alias #":" 2)] + [(first parts) (second parts)])) + +(defn validate-ledger-name + "Validates a ledger name for creation. Throws if invalid. + Rules: + - Cannot contain ':' (reserved for branch separator) + - Cannot contain '@', '#', '?' (reserved characters) + - Cannot contain whitespace + - Cannot start with '/', '-' + - Cannot end with '/' + - Cannot be empty + - Cannot contain path traversal patterns like '../'" + [ledger-name] + (cond + (str/blank? ledger-name) + (throw (ex-info "Ledger name cannot be empty" + {:error :db/invalid-ledger-name + :ledger-name ledger-name})) + + (str/includes? ledger-name ":") + (throw (ex-info (str "Ledger name cannot contain ':' character. " + "Branches must be created separately. " + "Provided: " ledger-name) + {:error :db/invalid-ledger-name + :ledger-name ledger-name})) + + (re-find #"[@#?]" ledger-name) + (throw (ex-info (str "Ledger name cannot contain '@', '#', or '?' characters. " + "Provided: " ledger-name) + {:error :db/invalid-ledger-name + :ledger-name ledger-name})) + + (re-find #"\s" ledger-name) + (throw (ex-info (str "Ledger name cannot contain whitespace. " + "Provided: " ledger-name) + {:error :db/invalid-ledger-name + :ledger-name ledger-name})) + + (str/ends-with? ledger-name "/") + (throw (ex-info (str "Ledger name cannot end with '/'. " + "Provided: " ledger-name) + {:error :db/invalid-ledger-name + :ledger-name ledger-name})) + + (re-matches #"^[/\-].*" ledger-name) + (throw (ex-info (str "Ledger name cannot start with '/' or '-'. " + "Provided: " ledger-name) + {:error :db/invalid-ledger-name + :ledger-name ledger-name})) + + (re-matches #"^/+$" ledger-name) + (throw (ex-info (str "Ledger name cannot consist only of '/' characters. " + "Provided: " ledger-name) + {:error :db/invalid-ledger-name + :ledger-name ledger-name})) + + (str/includes? ledger-name "../") + (throw (ex-info (str "Ledger name cannot contain path traversal patterns. " + "Provided: " ledger-name) + {:error :db/invalid-ledger-name + :ledger-name ledger-name})) + + (not (re-matches #"^[a-zA-Z0-9][\w\-\./_]*$" ledger-name)) + (throw (ex-info (str "Ledger name must start with alphanumeric character and " + "contain only alphanumeric, underscore, hyphen, dot, or slash characters. " + "Provided: " ledger-name) + {:error :db/invalid-ledger-name + :ledger-name ledger-name})) + + :else ledger-name)) + +(defn validate-branch-name + "Validates a branch name. Throws if invalid. + Rules: + - Cannot contain '/' (would create subdirectories) + - Cannot contain whitespace + - Should only contain alphanumeric characters, hyphens, underscores, and dots" + [branch-name] + (cond + (str/blank? branch-name) + (throw (ex-info "Branch name cannot be empty" + {:error :db/invalid-branch-name + :branch-name branch-name})) + + (str/includes? branch-name "/") + (throw (ex-info (str "Branch name cannot contain '/' character. " + "Provided: " branch-name) + {:error :db/invalid-branch-name + :branch-name branch-name})) + + (re-find #"\s" branch-name) + (throw (ex-info (str "Branch name cannot contain whitespace. " + "Provided: " branch-name) + {:error :db/invalid-branch-name + :branch-name branch-name})) + + (not (re-matches #"^[a-zA-Z0-9][\w\-\.]*$" branch-name)) + (throw (ex-info (str "Branch name must start with alphanumeric character and " + "contain only alphanumeric, underscore, hyphen, or dot characters. " + "Provided: " branch-name) + {:error :db/invalid-branch-name + :branch-name branch-name})) + + :else branch-name)) \ No newline at end of file diff --git a/src/fluree/db/virtual_graph/bm25/storage.clj b/src/fluree/db/virtual_graph/bm25/storage.clj index 368423abb4..62a4b1036a 100644 --- a/src/fluree/db/virtual_graph/bm25/storage.clj +++ b/src/fluree/db/virtual_graph/bm25/storage.clj @@ -4,6 +4,7 @@ [fluree.db.serde.protocol :as serde] [fluree.db.storage :as storage] [fluree.db.util.async :refer [js (fluree/status conn ledger-id))) - ([conn ledger-id branch] (clj->js (fluree/status conn ledger-id branch)))) + [conn ledger-id] + (clj->js (fluree/status conn ledger-id))) (defn ^:export db [conn ledger-id] diff --git a/src/fluree/sdk/node.cljs b/src/fluree/sdk/node.cljs index 46b665b78e..715b73553e 100644 --- a/src/fluree/sdk/node.cljs +++ b/src/fluree/sdk/node.cljs @@ -42,8 +42,8 @@ (js->clj opts :keywordize-keys true)))) (defn ^:export status - ([conn ledger-id] (clj->js (fluree/status conn ledger-id))) - ([conn ledger-id branch] (clj->js (fluree/status conn ledger-id branch)))) + [conn ledger-id] + (clj->js (fluree/status conn ledger-id))) (defn ^:export db [conn ledger-id] diff --git a/test/fluree/db/api/create_test.clj b/test/fluree/db/api/create_test.clj new file mode 100644 index 0000000000..937d11d90c --- /dev/null +++ b/test/fluree/db/api/create_test.clj @@ -0,0 +1,140 @@ +(ns fluree.db.api.create-test + "Tests for ledger creation validation and behavior" + (:require [clojure.test :refer [deftest is testing]] + [fluree.db.api :as fluree] + [fluree.db.test-utils :as test-utils] + [fluree.db.util :as util])) + +(deftest create-ledger-name-validation + (testing "Ledger creation name validation" + (let [conn (test-utils/create-conn)] + + (testing "rejects ledger names containing ':' character" + (is (thrown-with-msg? + clojure.lang.ExceptionInfo + #"Ledger name cannot contain ':' character" + (fluree/create conn "invalid:name")) + "Should reject name with colon") + + (try + (fluree/create conn "test:branch") + (is false "Should have thrown exception") + (catch clojure.lang.ExceptionInfo e + (is (= :db/invalid-ledger-name (-> e ex-data :error)) + "Should return correct error code"))) + + (is (thrown-with-msg? + clojure.lang.ExceptionInfo + #"Ledger name cannot contain ':' character" + (fluree/create conn "test:feature:v2")) + "Should reject name with multiple colons")) + + (testing "accepts valid ledger names" + (is (not (util/exception? @(fluree/create conn "valid-name"))) + "Should accept name with hyphen") + + (is (not (util/exception? @(fluree/create conn "valid_name"))) + "Should accept name with underscore") + + (is (not (util/exception? @(fluree/create conn "tenant/database"))) + "Should accept name with slash") + + (is (not (util/exception? @(fluree/create conn "my-ledger-2024"))) + "Should accept alphanumeric with special chars")) + + (testing "automatically appends ':main' branch to valid names" + (let [db @(fluree/create conn "auto-branch-test")] + (is (= "auto-branch-test:main" (get-in db [:commit :alias])) + "Should append :main to ledger name")))))) + +(deftest create-with-txn-ledger-name-validation + (testing "create-with-txn ledger name validation" + (let [conn (test-utils/create-conn)] + + (testing "rejects ledger names containing ':' character" + (let [txn-with-colon {"@context" {"ex" "http://example.org/"} + "ledger" "invalid:name" + "insert" {"@id" "ex:test" "ex:value" 1}}] + (is (util/exception? @(fluree/create-with-txn conn txn-with-colon)) + "Should reject name with colon")) + + (let [txn-with-branch {"@context" {"ex" "http://example.org/"} + "ledger" "test:branch" + "insert" {"@id" "ex:test" "ex:value" 1}} + result @(fluree/create-with-txn conn txn-with-branch)] + (is (util/exception? result) + "Should reject name with branch") + (is (= :db/invalid-ledger-name + (-> result ex-data :error)) + "Should return correct error code"))) + + (testing "accepts valid ledger names and creates with initial data" + (let [db @(fluree/create-with-txn conn + {"@context" {"ex" "http://example.org/"} + "ledger" "txn-test" + "insert" {"@id" "ex:alice" "ex:age" 42}})] + (is (= "txn-test:main" (get-in db [:commit :alias])) + "Should create ledger with :main branch") + + ;; Verify the initial data was inserted + (let [result @(fluree/query db + {"@context" {"ex" "http://example.org/"} + "select" {"ex:alice" ["*"]}})] + (is (= 42 (-> result first (get "ex:age"))) + "Should have inserted initial data"))))))) + +(deftest edge-case-validation + (testing "Edge cases for ledger name validation" + (let [conn (test-utils/create-conn)] + + (testing "empty colon cases" + (is (thrown-with-msg? + clojure.lang.ExceptionInfo + #"Ledger name cannot contain ':' character" + (fluree/create conn ":")) + "Should reject single colon") + + (is (thrown-with-msg? + clojure.lang.ExceptionInfo + #"Ledger name cannot contain ':' character" + (fluree/create conn ":branch")) + "Should reject name starting with colon") + + (is (thrown-with-msg? + clojure.lang.ExceptionInfo + #"Ledger name cannot contain ':' character" + (fluree/create conn "ledger:")) + "Should reject name ending with colon")) + + (testing "special characters that ARE allowed" + (is (not (util/exception? @(fluree/create conn "ledger.with.dots"))) + "Should accept dots") + + (is (not (util/exception? @(fluree/create conn "ledger-with-dashes"))) + "Should accept dashes") + + (is (not (util/exception? @(fluree/create conn "ledger_with_underscores"))) + "Should accept underscores") + + (is (not (util/exception? @(fluree/create conn "org/department/project"))) + "Should accept multiple slashes"))))) + +(deftest duplicate-ledger-creation + (testing "Cannot create duplicate ledgers" + (let [conn (test-utils/create-conn) + ledger-name "unique-test"] + + ;; First creation should succeed + (is (not (util/exception? @(fluree/create conn ledger-name))) + "First creation should succeed") + + ;; Second creation with same name should fail + (is (util/exception? @(fluree/create conn ledger-name)) + "Duplicate creation should fail") + + ;; Trying with explicit :main should be rejected by validation + (is (thrown-with-msg? + clojure.lang.ExceptionInfo + #"Ledger name cannot contain ':' character" + (fluree/create conn (str ledger-name ":main"))) + "Should reject explicit :main branch in name")))) \ No newline at end of file diff --git a/test/fluree/db/nameservice_query_test.clj b/test/fluree/db/nameservice_query_test.clj index 092ea045aa..6f793a476d 100644 --- a/test/fluree/db/nameservice_query_test.clj +++ b/test/fluree/db/nameservice_query_test.clj @@ -4,6 +4,7 @@ [clojure.string :as str] [clojure.test :refer [deftest is testing]] [fluree.db.api :as fluree] + [fluree.db.constants :as const] [fluree.db.json-ld.iri :as iri])) (deftest nameservice-query-test @@ -196,17 +197,19 @@ (testing "Verify file system structure" ;; Check that subdirectories were created correctly - (let [ns-dir (io/file (str storage-path) "ns@v1") + (let [ns-dir (io/file (str storage-path) const/ns-version) + ;; With ledger names like "tenant1/customers", the structure is: + ;; ns@v2/tenant1/customers/main.json tenant1-dir (io/file ns-dir "tenant1") tenant2-dir (io/file ns-dir "tenant2")] - (is (.exists ns-dir) "ns@v1 directory should exist") + (is (.exists ns-dir) (str const/ns-version " directory should exist")) (is (.exists tenant1-dir) "tenant1 subdirectory should exist") (is (.exists tenant2-dir) "tenant2 subdirectory should exist") - ;; Check for nameservice files - (let [customer-file (io/file ns-dir "tenant1/customers@main.json") - products-file (io/file ns-dir "tenant1/products@main.json") - orders-file (io/file ns-dir "tenant2/orders@main.json")] + ;; Check for nameservice files with new structure + (let [customer-file (io/file ns-dir "tenant1/customers/main.json") + products-file (io/file ns-dir "tenant1/products/main.json") + orders-file (io/file ns-dir "tenant2/orders/main.json")] (is (.exists customer-file) "Customer nameservice file should exist") (is (.exists products-file) "Products nameservice file should exist") (is (.exists orders-file) "Orders nameservice file should exist")))) diff --git a/test/fluree/db/query/history_test.clj b/test/fluree/db/query/history_test.clj index b6707811d3..4bcc3175cf 100644 --- a/test/fluree/db/query/history_test.clj +++ b/test/fluree/db/query/history_test.clj @@ -305,8 +305,7 @@ [{:f/commit {"https://www.w3.org/2018/credentials#issuer" {:id test-utils/did?} :f/address test-utils/address? - :f/alias "committest" - :f/branch "main" + :f/alias "committest:main" :f/previous {:id test-utils/commit-id?} :f/data {:f/address test-utils/address? @@ -319,15 +318,14 @@ :f/t 1 :id test-utils/db-id?} :f/time 720000 - :f/v 1 + :f/v 2 :id test-utils/commit-id?}}] @(fluree/history conn ledger-id {:context context :commit-details true :t {:from 1 :to 1}}))) (let [commit-5 {:f/commit {"https://www.w3.org/2018/credentials#issuer" {:id test-utils/did?} :f/address test-utils/address? - :f/alias "committest" - :f/branch "main" + :f/alias "committest:main" :f/data {:f/address test-utils/address? :f/assert [{:ex/x "foo-cat" :ex/y "bar-cat" @@ -342,13 +340,12 @@ :f/message "meow" :f/previous {:id test-utils/commit-id?} :f/time 720000 - :f/v 1 + :f/v 2 :id test-utils/commit-id?}} commit-4 {:f/commit {"https://www.w3.org/2018/credentials#issuer" {:id test-utils/did?} :f/address test-utils/address? - :f/alias "committest" - :f/branch "main" + :f/alias "committest:main" :f/data {:f/address test-utils/address? :f/assert [{:ex/x "foo-cat" :ex/y "bar-cat" @@ -360,7 +357,7 @@ :id test-utils/db-id?} :f/previous {:id test-utils/commit-id?} :f/time 720000 - :f/v 1 + :f/v 2 :id test-utils/commit-id?}}] (is (pred-match? [commit-4 commit-5] @@ -385,8 +382,7 @@ {:f/commit {"https://www.w3.org/2018/credentials#issuer" {:id test-utils/did?} :f/address test-utils/address? - :f/alias "committest" - :f/branch "main" + :f/alias "committest:main" :f/data {:f/address test-utils/address? :f/assert [{:ex/x "foo-cat" :ex/y "bar-cat" @@ -398,15 +394,14 @@ :id test-utils/db-id?} :f/previous {:id test-utils/commit-id?} :f/time 720000 - :f/v 1 + :f/v 2 :id test-utils/commit-id?}} c4))) (is (pred-match? {:f/commit {"https://www.w3.org/2018/credentials#issuer" {:id test-utils/did?} :f/address test-utils/address? - :f/alias "committest" - :f/branch "main" + :f/alias "committest:main" :f/data {:f/address test-utils/address? :f/assert [{:ex/x "foo-3" :ex/y "bar-3" @@ -420,15 +415,14 @@ :id test-utils/db-id?} :f/previous {:id test-utils/commit-id?} :f/time 720000 - :f/v 1 + :f/v 2 :id test-utils/commit-id?}} c3)) (is (pred-match? {:f/commit {"https://www.w3.org/2018/credentials#issuer" {:id test-utils/did?} :f/address test-utils/address? - :f/alias "committest" - :f/branch "main" + :f/alias "committest:main" :f/data {:f/address test-utils/address? :f/assert [{:ex/x "foo-2" :ex/y "bar-2" @@ -442,7 +436,7 @@ :id test-utils/db-id?} :f/previous {:id test-utils/commit-id?} :f/time 720000 - :f/v 1 + :f/v 2 :id test-utils/commit-id?}} c2)))) @@ -451,8 +445,7 @@ [{:f/commit {"https://www.w3.org/2018/credentials#issuer" {:id test-utils/did?} :f/address test-utils/address? - :f/alias "committest" - :f/branch "main" + :f/alias "committest:main" :f/data {:f/address test-utils/address? :f/assert [{:ex/x "foo-cat" :ex/y "bar-cat" @@ -465,13 +458,12 @@ :id test-utils/db-id?} :f/previous {:id test-utils/commit-id?} :f/time 720000 - :f/v 1 + :f/v 2 :id test-utils/commit-id?}} {:f/commit {"https://www.w3.org/2018/credentials#issuer" {:id test-utils/did?} :f/address test-utils/address? - :f/alias "committest" - :f/branch "main" + :f/alias "committest:main" :f/data {:f/address test-utils/address? :f/assert [{:ex/x "foo-cat" :ex/y "bar-cat" @@ -487,7 +479,7 @@ :f/message "meow" :f/previous {:id test-utils/commit-id?} :f/time 720000 - :f/v 1 + :f/v 2 :id test-utils/commit-id?}}] @(fluree/history conn ledger-id {:context context :commit-details true @@ -498,8 +490,7 @@ [{:f/commit {"https://www.w3.org/2018/credentials#issuer" {:id test-utils/did?} :f/address test-utils/address? - :f/alias "committest" - :f/branch "main" + :f/alias "committest:main" :f/previous {:id test-utils/commit-id?} :f/data {:f/address test-utils/address? :f/assert [{:ex/x "foo-1" @@ -511,7 +502,7 @@ :f/t 1 :id test-utils/db-id?} :f/time 720000 - :f/v 1 + :f/v 2 :id test-utils/commit-id?}}] @(fluree/history conn ledger-id {:context context :commit-details true @@ -525,8 +516,7 @@ :commit {"https://www.w3.org/2018/credentials#issuer" {:id test-utils/did?} :f/address test-utils/address? - :f/alias "committest" - :f/branch "main" + :f/alias "committest:main" :f/data {:f/address test-utils/address? :f/assert [{:ex/x "foo-3" :ex/y "bar-3" @@ -540,7 +530,7 @@ :id test-utils/db-id?} :f/previous {:id test-utils/commit-id?} :f/time 720000 - :f/v 1 + :f/v 2 :id test-utils/commit-id?} :retract [{:ex/x "foo-2" :ex/y "bar-2" @@ -552,8 +542,7 @@ :commit {"https://www.w3.org/2018/credentials#issuer" {:id test-utils/did?} :f/address test-utils/address? - :f/alias "committest" - :f/branch "main" + :f/alias "committest:main" :f/data {:f/address test-utils/address? :f/assert [{:ex/x "foo-cat" :ex/y "bar-cat" @@ -642,13 +631,12 @@ :ex/y "bar-3" :id :ex/alice}] :commit {:f/address test-utils/address? - :f/alias ledger-name - :f/branch "main" + :f/alias (str ledger-name ":main") :f/data {:f/address test-utils/address? :f/assert [{:ex/x "foo-3" :ex/y "bar-3" :id :ex/alice}] - :f/flakes 34 + :f/flakes 32 :f/previous {:id test-utils/db-id?} :f/retract [{:ex/x "foo-2" :ex/y "bar-2" @@ -658,7 +646,7 @@ :id test-utils/db-id?} :f/previous {:id test-utils/commit-id?} :f/time 720000 - :f/v 1 + :f/v 2 :id test-utils/commit-id?} :retract [{:ex/x "foo-2" :ex/y "bar-2" @@ -668,13 +656,12 @@ :ex/y "bar-cat" :id :ex/alice}] :commit {:f/address test-utils/address? - :f/alias ledger-name - :f/branch "main" + :f/alias (str ledger-name ":main") :f/data {:f/address test-utils/address? :f/assert [{:ex/x "foo-cat" :ex/y "bar-cat" :id :ex/alice}] - :f/flakes 64 + :f/flakes 62 :f/previous {:id test-utils/db-id?} :f/retract [{:ex/x "foo-3" :ex/y "bar-3" @@ -685,7 +672,7 @@ :f/message "meow" :f/previous {:id test-utils/commit-id?} :f/time 720000 - :f/v 1 + :f/v 2 :id test-utils/commit-id?} :retract [{:ex/x "foo-3" :ex/y "bar-3" @@ -735,13 +722,12 @@ :commit {"https://www.w3.org/2018/credentials#issuer" {:id test-utils/did?} :f/address test-utils/address? - :f/alias ledger-name - :f/branch "main" + :f/alias (str ledger-name ":main") :f/data {:f/address test-utils/address? :f/assert [{:ex/x "foo-3" :ex/y "bar-3" :id :ex/alice}] - :f/flakes 32 + :f/flakes 30 :f/previous {:id test-utils/db-id?} :f/retract [{:ex/x "foo-2" :ex/y "bar-2" @@ -751,7 +737,7 @@ :id test-utils/db-id?} :f/previous {:id test-utils/commit-id?} :f/time 720000 - :f/v 1 + :f/v 2 :id test-utils/commit-id?} :retract [{:ex/x "foo-2" :ex/y "bar-2" @@ -763,8 +749,7 @@ :commit {"https://www.w3.org/2018/credentials#issuer" {:id test-utils/did?} :f/address test-utils/address? - :f/alias ledger-name - :f/branch "main" + :f/alias (str ledger-name ":main") :f/data {:f/address test-utils/address? :f/assert [{:ex/x "foo-cat" :ex/y "bar-cat" @@ -780,7 +765,7 @@ :f/message "meow" :f/previous {:id test-utils/commit-id?} :f/time 720000 - :f/v 1 + :f/v 2 :id test-utils/commit-id?} :retract [{:ex/x "foo-3" :ex/y "bar-3" @@ -844,13 +829,12 @@ :id :ex/alice}] :commit {:cred/issuer {:id test-utils/did?} :f/address test-utils/address? - :f/alias ledger-name - :f/branch "main" + :f/alias (str ledger-name ":main") :f/data {:f/address test-utils/address? :f/assert [{:ex/x "foo-3" :ex/y "bar-3" :id :ex/alice}] - :f/flakes 34 + :f/flakes 32 :f/retract [{:ex/x "foo-2" :ex/y "bar-2" :id :ex/alice}] @@ -859,7 +843,7 @@ :id test-utils/db-id?} :f/previous {:id test-utils/commit-id?} :f/time 720000 - :f/v 1 + :f/v 2 :id test-utils/commit-id?} :retract [{:ex/x "foo-2" :ex/y "bar-2" @@ -870,13 +854,12 @@ :id :ex/alice}] :commit {:cred/issuer {:id test-utils/did?} :f/address test-utils/address? - :f/alias ledger-name - :f/branch "main" + :f/alias (str ledger-name ":main") :f/data {:f/address test-utils/address? :f/assert [{:ex/x "foo-cat" :ex/y "bar-cat" :id :ex/alice}] - :f/flakes 64 + :f/flakes 60 :f/retract [{:ex/x "foo-3" :ex/y "bar-3" :id :ex/alice}] @@ -886,7 +869,7 @@ :f/message "meow" :f/previous {:id test-utils/commit-id?} :f/time 720000 - :f/v 1 + :f/v 2 :id test-utils/commit-id?} :retract [{:ex/x "foo-3" :ex/y "bar-3" @@ -1024,7 +1007,7 @@ "f:time" 720000, "f:previous" {"id" test-utils/commit-id?}, "id" test-utils/commit-id? - "f:v" 1, + "f:v" 2, "f:branch" "main", "f:address" test-utils/address? "f:data" {"f:address" test-utils/address? @@ -1040,7 +1023,7 @@ "f:txn" test-utils/address? "f:previous" {"id" test-utils/commit-id?} "id" test-utils/commit-id? - "f:v" 1, + "f:v" 2, "f:branch" "main", "f:address" test-utils/address? "f:data" {"f:address" test-utils/address? @@ -1056,7 +1039,7 @@ "f:txn" test-utils/address? "f:previous" {"id" test-utils/commit-id?}, "id" test-utils/commit-id? - "f:v" 1, + "f:v" 2, "f:branch" "main", "f:address" test-utils/address? "f:data" {"f:address" test-utils/address? @@ -1107,7 +1090,7 @@ "f:time" 720000, "f:previous" {"id" test-utils/commit-id?}, "id" test-utils/commit-id? - "f:v" 1, + "f:v" 2, "f:branch" "main", "f:address" test-utils/address? "f:data" @@ -1145,7 +1128,7 @@ "f:txn" test-utils/address? "f:previous" {"id" test-utils/commit-id?}, "id" test-utils/commit-id? - "f:v" 1, + "f:v" 2, "f:branch" "main", "f:address" test-utils/address? "f:data" @@ -1165,7 +1148,7 @@ "f:txn" test-utils/address? "f:previous" {"id" test-utils/commit-id?}, "id" test-utils/commit-id? - "f:v" 1, + "f:v" 2, "f:branch" "main", "f:address" test-utils/address? "f:data" @@ -1197,7 +1180,7 @@ "f:time" 720000, "f:previous" {"id" test-utils/commit-id?}, "id" test-utils/commit-id? - "f:v" 1, + "f:v" 2, "f:branch" "main", "f:address" test-utils/address? "f:data" @@ -1248,7 +1231,7 @@ "f:time" 720000, "f:previous" {"id" test-utils/commit-id?}, "id" test-utils/commit-id? - "f:v" 1, + "f:v" 2, "f:branch" "main", "f:address" test-utils/address? "f:data" diff --git a/test/fluree/db/query/misc_queries_test.clj b/test/fluree/db/query/misc_queries_test.clj index 1377a9a785..bf48ec4c8a 100644 --- a/test/fluree/db/query/misc_queries_test.clj +++ b/test/fluree/db/query/misc_queries_test.clj @@ -170,37 +170,23 @@ result @(fluree/query db* {:context [test-utils/default-context {:ex "http://example.org/ns/"}] :select ['?s '?p '?o] - :where {:id '?s, '?p '?o}})] - (is (= [["fluree:db:sha256:btqomzs3uzs7dspzbs5ht4e7af7qrahnvomx4s4id7apr5jm7dxn" - :f/address - "fluree:memory://tqomzs3uzs7dspzbs5ht4e7af7qrahnvomx4s4id7apr5jm7dxn"] - ["fluree:db:sha256:btqomzs3uzs7dspzbs5ht4e7af7qrahnvomx4s4id7apr5jm7dxn" :f/flakes 11] - ["fluree:db:sha256:btqomzs3uzs7dspzbs5ht4e7af7qrahnvomx4s4id7apr5jm7dxn" :f/size 1266] - ["fluree:db:sha256:btqomzs3uzs7dspzbs5ht4e7af7qrahnvomx4s4id7apr5jm7dxn" :f/t 1] - ["fluree:commit:sha256:bbzz6o53rstn4bwdgn54bkgvoins246lzgol6ose4g4snupoyyeew" - "https://www.w3.org/2018/credentials#issuer" - "did:key:z6Mkf2bJEm3KiDeCzrxbQDvT8jfYiz5t2Lo3fuvwPL6E6duw"] - ["fluree:commit:sha256:bbzz6o53rstn4bwdgn54bkgvoins246lzgol6ose4g4snupoyyeew" - :f/address - "fluree:memory://bzz6o53rstn4bwdgn54bkgvoins246lzgol6ose4g4snupoyyeew"] - ["fluree:commit:sha256:bbzz6o53rstn4bwdgn54bkgvoins246lzgol6ose4g4snupoyyeew" - :f/alias - "query/everything"] - ["fluree:commit:sha256:bbzz6o53rstn4bwdgn54bkgvoins246lzgol6ose4g4snupoyyeew" - :f/branch - "main"] - ["fluree:commit:sha256:bbzz6o53rstn4bwdgn54bkgvoins246lzgol6ose4g4snupoyyeew" - :f/data - "fluree:db:sha256:btqomzs3uzs7dspzbs5ht4e7af7qrahnvomx4s4id7apr5jm7dxn"] - ["fluree:commit:sha256:bbzz6o53rstn4bwdgn54bkgvoins246lzgol6ose4g4snupoyyeew" - :f/previous - "fluree:commit:sha256:bb6dtkig73qu77wvwzpumlkmy2ftq3ikv2lhltti4eqvripnpqoqz"] - ["fluree:commit:sha256:bbzz6o53rstn4bwdgn54bkgvoins246lzgol6ose4g4snupoyyeew" - :f/time - 720000] - ["fluree:commit:sha256:bbzz6o53rstn4bwdgn54bkgvoins246lzgol6ose4g4snupoyyeew" - :f/v - 1] + :where {:id '?s, '?p '?o}}) + expected-commit-id "fluree:commit:sha256:bbssolklwzebg6jgcjki3bsg3wbnybtzvaqymkai5loz7sixr4iav" + expected-commit-addr "fluree:memory://bssolklwzebg6jgcjki3bsg3wbnybtzvaqymkai5loz7sixr4iav" + expected-commit-previous "fluree:commit:sha256:bsx5gbgyyigspr2yuswue4lprez7ykj63n7gmpb3nzfzbs7f5bvo" + expected-db-id "fluree:db:sha256:btqomzs3uzs7dspzbs5ht4e7af7qrahnvomx4s4id7apr5jm7dxn" + expected-db-addr "fluree:memory://tqomzs3uzs7dspzbs5ht4e7af7qrahnvomx4s4id7apr5jm7dxn"] + (is (= [[expected-db-id :f/address expected-db-addr] + [expected-db-id :f/flakes 11] + [expected-db-id :f/size 1266] + [expected-db-id :f/t 1] + [expected-commit-id "https://www.w3.org/2018/credentials#issuer" "did:key:z6Mkf2bJEm3KiDeCzrxbQDvT8jfYiz5t2Lo3fuvwPL6E6duw"] + [expected-commit-id :f/address expected-commit-addr] + [expected-commit-id :f/alias "query/everything:main"] + [expected-commit-id :f/data expected-db-id] + [expected-commit-id :f/previous expected-commit-previous] + [expected-commit-id :f/time 720000] + [expected-commit-id :f/v 2] [:ex/alice :type :ex/User] [:ex/alice :schema/age 42] [:ex/alice :schema/email "alice@flur.ee"] diff --git a/test/fluree/db/query/property_path_test.clj b/test/fluree/db/query/property_path_test.clj index a76203e4ea..f996d8b969 100644 --- a/test/fluree/db/query/property_path_test.clj +++ b/test/fluree/db/query/property_path_test.clj @@ -4,11 +4,11 @@ (deftest transitive-paths (let [conn @(fluree/connect-memory) - db0 @(fluree/create conn "property/path") - db0 db0] + db0 @(fluree/create conn "property/path")] (testing "one+" (testing "no variables" - (let [db1 @(fluree/update db0 {"insert" + (let [db1 @(fluree/update db0 {"@context" {"ex" "http://example.org/"} + "insert" [{"@id" "ex:a" "ex:y" [{"@id" "ex:b" "ex:y" {"@id" "ex:c" @@ -22,17 +22,20 @@ "ex:y" {"@id" "ex:k"}}]}]}]})] (testing "non-transitive" (is (= [] - @(fluree/query db1 {"where" [{"@id" "ex:a" "ex:y" {"@id" "ex:f"}}] + @(fluree/query db1 {"@context" {"ex" "http://example.org/"} + "where" [{"@id" "ex:a" "ex:y" {"@id" "ex:f"}}] "select" {"ex:a" ["*"]}})))) (testing "transitive" - (let [result @(fluree/query db1 {"where" [{"@id" "ex:a" "" {"@id" "ex:f"}}] + (let [result @(fluree/query db1 {"@context" {"ex" "http://example.org/"} + "where" [{"@id" "ex:a" "" {"@id" "ex:f"}}] "select" {"ex:a" ["*"]}})] (is (= {:status 400, :error :db/unsupported-transitive-path} (ex-data result))) (is (= "Unsupported transitive path." (ex-message result))))))) (testing "object variable" - (let [db1 @(fluree/update db0 {"insert" + (let [db1 @(fluree/update db0 {"@context" {"ex" "http://example.org/"} + "insert" [{"@id" "ex:a" "ex:knows" {"@id" "ex:b" "ex:knows" [{"@id" "ex:c"} @@ -40,20 +43,25 @@ "ex:knows" {"@id" "ex:e"}}]}}]})] (testing "non-transitive" (is (= ["ex:b"] - @(fluree/query db1 {"where" [{"@id" "ex:a" "ex:knows" "?who"}] + @(fluree/query db1 {"@context" {"ex" "http://example.org/"} + "where" [{"@id" "ex:a" "ex:knows" "?who"}] "select" "?who"})))) (testing "transitive" (testing "without cycle" (is (= ["ex:b" "ex:c" "ex:d" "ex:e"] - @(fluree/query db1 {"where" [{"@id" "ex:a" "<+>" "?who"}] + @(fluree/query db1 {"@context" {"ex" "http://example.org/"} + "where" [{"@id" "ex:a" "<+>" "?who"}] "select" "?who"})))) (testing "with cycle" - (let [db2 @(fluree/update db1 {"insert" {"@id" "ex:e" "ex:knows" {"@id" "ex:a"}}})] + (let [db2 @(fluree/update db1 {"@context" {"ex" "http://example.org/"} + "insert" {"@id" "ex:e" "ex:knows" {"@id" "ex:a"}}})] (is (= ["ex:b" "ex:c" "ex:d" "ex:e" "ex:a"] - @(fluree/query db2 {"where" [{"@id" "ex:a" "" "?who"}] + @(fluree/query db2 {"@context" {"ex" "http://example.org/"} + "where" [{"@id" "ex:a" "" "?who"}] "select" "?who"})))))))) (testing "subject variable" - (let [db1 @(fluree/update db0 {"insert" + (let [db1 @(fluree/update db0 {"@context" {"ex" "http://example.org/"} + "insert" [{"@id" "ex:a" "ex:knows" {"@id" "ex:b" "ex:knows" [{"@id" "ex:c"} @@ -61,52 +69,62 @@ "ex:knows" {"@id" "ex:e"}}]}}]})] (testing "non-transitive" (is (= ["ex:d"] - @(fluree/query db1 {"where" [{"@id" "?who" "ex:knows" {"@id" "ex:e"}}] + @(fluree/query db1 {"@context" {"ex" "http://example.org/"} + "where" [{"@id" "?who" "ex:knows" {"@id" "ex:e"}}] "select" "?who"})))) (testing "transitive" (testing "without cycle" (is (= ["ex:d" "ex:b" "ex:a"] - @(fluree/query db1 {"where" [{"@id" "?who" "" {"@id" "ex:e"}}] + @(fluree/query db1 {"@context" {"ex" "http://example.org/"} + "where" [{"@id" "?who" "" {"@id" "ex:e"}}] "select" "?who"})))) (testing "with cycle" - (let [db2 @(fluree/update db1 {"insert" {"@id" "ex:e" "ex:knows" {"@id" "ex:a"}}})] + (let [db2 @(fluree/update db1 {"@context" {"ex" "http://example.org/"} + "insert" {"@id" "ex:e" "ex:knows" {"@id" "ex:a"}}})] (is (= ["ex:d" "ex:b" "ex:a" "ex:e"] - @(fluree/query db2 {"where" [{"@id" "?who" "" {"@id" "ex:e"}}] + @(fluree/query db2 {"@context" {"ex" "http://example.org/"} + "where" [{"@id" "?who" "" {"@id" "ex:e"}}] "select" "?who"})))))))) (testing "subject and object variable" (let [db1 @(fluree/update db0 - {"insert" + {"@context" {"ex" "http://example.org/"} + "insert" [{"@id" "ex:1" "ex:knows" {"@id" "ex:2" "ex:knows" {"@id" "ex:3"}}}]})] (testing "non-transitive" (is (= [["ex:1" "ex:2"] ["ex:2" "ex:3"]] - @(fluree/query db1 {"where" [{"@id" "?s" "ex:knows" "?o"}] + @(fluree/query db1 {"@context" {"ex" "http://example.org/"} + "where" [{"@id" "?s" "ex:knows" "?o"}] "select" ["?s" "?o"]})))) (testing "transitive" (testing "without cycle" - (is (= [["ex:1" "ex:2"] - ["ex:2" "ex:3"] - ["ex:1" "ex:3"]] - @(fluree/query db1 {"where" [{"@id" "?x" "" "?y"}] - "select" ["?x" "?y"]})))) + (is (= #{["ex:1" "ex:2"] + ["ex:2" "ex:3"] + ["ex:1" "ex:3"]} + (set @(fluree/query db1 {"@context" {"ex" "http://example.org/"} + "where" [{"@id" "?x" "" "?y"}] + "select" ["?x" "?y"]}))))) (testing "with cycle" - (let [db2 @(fluree/update db1 {"insert" {"@id" "ex:3" "ex:knows" {"@id" "ex:1"}}})] - (is (= [["ex:3" "ex:2"] - ["ex:1" "ex:2"] - ["ex:2" "ex:3"] - ["ex:1" "ex:3"] - ["ex:2" "ex:2"] - ["ex:3" "ex:3"] - ["ex:3" "ex:1"] - ["ex:2" "ex:1"] - ["ex:1" "ex:1"]] - @(fluree/query db2 {"where" [{"@id" "?x" "" "?y"}] - "select" ["?x" "?y"]}))))))))) + (let [db2 @(fluree/update db1 {"@context" {"ex" "http://example.org/"} + "insert" {"@id" "ex:3" "ex:knows" {"@id" "ex:1"}}})] + (is (= #{["ex:3" "ex:2"] + ["ex:1" "ex:2"] + ["ex:2" "ex:3"] + ["ex:1" "ex:3"] + ["ex:2" "ex:2"] + ["ex:3" "ex:3"] + ["ex:3" "ex:1"] + ["ex:2" "ex:1"] + ["ex:1" "ex:1"]} + (set @(fluree/query db2 {"@context" {"ex" "http://example.org/"} + "where" [{"@id" "?x" "" "?y"}] + "select" ["?x" "?y"]})))))))))) (testing "zero+" (testing "no variables" - (let [db1 @(fluree/update db0 {"insert" + (let [db1 @(fluree/update db0 {"@context" {"ex" "http://example.org/"} + "insert" [{"@id" "ex:a" "ex:y" [{"@id" "ex:b" "ex:y" {"@id" "ex:c" @@ -120,17 +138,20 @@ "ex:y" {"@id" "ex:k"}}]}]}]})] (testing "non-transitive" (is (= [] - @(fluree/query db1 {"where" [{"@id" "ex:a" "ex:y" {"@id" "ex:f"}}] + @(fluree/query db1 {"@context" {"ex" "http://example.org/"} + "where" [{"@id" "ex:a" "ex:y" {"@id" "ex:f"}}] "select" {"ex:a" ["*"]}})))) (testing "transitive" - (let [result @(fluree/query db1 {"where" [{"@id" "ex:a" "" {"@id" "ex:f"}}] + (let [result @(fluree/query db1 {"@context" {"ex" "http://example.org/"} + "where" [{"@id" "ex:a" "" {"@id" "ex:f"}}] "select" {"ex:a" ["*"]}})] (is (= {:status 400, :error :db/unsupported-transitive-path} (ex-data result))) (is (= "Unsupported transitive path." (ex-message result))))))) (testing "object variable" - (let [db1 @(fluree/update db0 {"insert" + (let [db1 @(fluree/update db0 {"@context" {"ex" "http://example.org/"} + "insert" [{"@id" "ex:a" "ex:knows" {"@id" "ex:b" "ex:knows" [{"@id" "ex:c"} @@ -138,20 +159,25 @@ "ex:knows" {"@id" "ex:e"}}]}}]})] (testing "non-transitive" (is (= ["ex:b"] - @(fluree/query db1 {"where" [{"@id" "ex:a" "ex:knows" "?who"}] + @(fluree/query db1 {"@context" {"ex" "http://example.org/"} + "where" [{"@id" "ex:a" "ex:knows" "?who"}] "select" "?who"})))) (testing "transitive" (testing "without cycle" (is (= ["ex:a" "ex:b" "ex:c" "ex:d" "ex:e"] - @(fluree/query db1 {"where" [{"@id" "ex:a" "" "?who"}] + @(fluree/query db1 {"@context" {"ex" "http://example.org/"} + "where" [{"@id" "ex:a" "" "?who"}] "select" "?who"})))) (testing "with cycle" - (let [db2 @(fluree/update db1 {"insert" {"@id" "ex:e" "ex:knows" {"@id" "ex:a"}}})] + (let [db2 @(fluree/update db1 {"@context" {"ex" "http://example.org/"} + "insert" {"@id" "ex:e" "ex:knows" {"@id" "ex:a"}}})] (is (= ["ex:a" "ex:b" "ex:c" "ex:d" "ex:e"] - @(fluree/query db2 {"where" [{"@id" "ex:a" "" "?who"}] + @(fluree/query db2 {"@context" {"ex" "http://example.org/"} + "where" [{"@id" "ex:a" "" "?who"}] "select" "?who"})))))))) (testing "subject variable" - (let [db1 @(fluree/update db0 {"insert" + (let [db1 @(fluree/update db0 {"@context" {"ex" "http://example.org/"} + "insert" [{"@id" "ex:a" "ex:knows" {"@id" "ex:b" "ex:knows" [{"@id" "ex:c"} @@ -159,28 +185,34 @@ "ex:knows" {"@id" "ex:e"}}]}}]})] (testing "non-transitive" (is (= ["ex:d"] - @(fluree/query db1 {"where" [{"@id" "?who" "ex:knows" {"@id" "ex:e"}}] + @(fluree/query db1 {"@context" {"ex" "http://example.org/"} + "where" [{"@id" "?who" "ex:knows" {"@id" "ex:e"}}] "select" "?who"})))) (testing "transitive" (testing "without cycle" (is (= ["ex:e" "ex:d" "ex:b" "ex:a"] - @(fluree/query db1 {"where" [{"@id" "?who" "" {"@id" "ex:e"}}] + @(fluree/query db1 {"@context" {"ex" "http://example.org/"} + "where" [{"@id" "?who" "" {"@id" "ex:e"}}] "select" "?who"})))) (testing "with cycle" - (let [db2 @(fluree/update db1 {"insert" {"@id" "ex:e" "ex:knows" {"@id" "ex:a"}}})] + (let [db2 @(fluree/update db1 {"@context" {"ex" "http://example.org/"} + "insert" {"@id" "ex:e" "ex:knows" {"@id" "ex:a"}}})] (is (= ["ex:e" "ex:d" "ex:b" "ex:a"] - @(fluree/query db2 {"where" [{"@id" "?who" "" {"@id" "ex:e"}}] + @(fluree/query db2 {"@context" {"ex" "http://example.org/"} + "where" [{"@id" "?who" "" {"@id" "ex:e"}}] "select" "?who"})))))))) (testing "subject and object variable" (let [db1 @(fluree/update db0 - {"insert" + {"@context" {"ex" "http://example.org/"} + "insert" [{"@id" "ex:1" "ex:knows" {"@id" "ex:2" "ex:knows" {"@id" "ex:3"}}}]})] (testing "non-transitive" (is (= [["ex:1" "ex:2"] ["ex:2" "ex:3"]] - @(fluree/query db1 {"where" [{"@id" "?s" "ex:knows" "?o"}] + @(fluree/query db1 {"@context" {"ex" "http://example.org/"} + "where" [{"@id" "?s" "ex:knows" "?o"}] "select" ["?s" "?o"]})))) (testing "transitive" (testing "without cycle" @@ -190,11 +222,13 @@ ["ex:2" "ex:2"] ["ex:2" "ex:3"] ["ex:3" "ex:3"]] - (sort @(fluree/query db1 {"where" [{"@id" "?x" "" "?y"}] + (sort @(fluree/query db1 {"@context" {"ex" "http://example.org/"} + "where" [{"@id" "?x" "" "?y"}] "select" ["?x" "?y"]}))))) (testing "disjoint subgraphs" (let [db2 @(fluree/update db1 - {"insert" + {"@context" {"ex" "http://example.org/"} + "insert" [{"@id" "ex:4" "ex:knows" {"@id" "ex:5" "ex:knows" {"@id" "ex:6"}}}]})] @@ -211,10 +245,12 @@ ["ex:5" "ex:5"] ["ex:5" "ex:6"] ["ex:6" "ex:6"]} - (set @(fluree/query db2 {"where" [{"@id" "?x" "" "?y"}] + (set @(fluree/query db2 {"@context" {"ex" "http://example.org/"} + "where" [{"@id" "?x" "" "?y"}] "select" ["?x" "?y"]})))))) (testing "with cycle" - (let [db2 @(fluree/update db1 {"insert" {"@id" "ex:3" "ex:knows" {"@id" "ex:1"}}})] + (let [db2 @(fluree/update db1 {"@context" {"ex" "http://example.org/"} + "insert" {"@id" "ex:3" "ex:knows" {"@id" "ex:1"}}})] (is (= [["ex:1" "ex:1"] ["ex:1" "ex:2"] ["ex:1" "ex:3"] @@ -226,5 +262,6 @@ ["ex:3" "ex:1"] ["ex:3" "ex:2"] ["ex:3" "ex:3"]] - (sort @(fluree/query db2 {"where" [{"@id" "?x" "" "?y"}] + (sort @(fluree/query db2 {"@context" {"ex" "http://example.org/"} + "where" [{"@id" "?x" "" "?y"}] "select" ["?x" "?y"]})))))))))))) diff --git a/test/fluree/db/query/stable_hashes_test.clj b/test/fluree/db/query/stable_hashes_test.clj index 1a4a79bdf7..66690c9492 100644 --- a/test/fluree/db/query/stable_hashes_test.clj +++ b/test/fluree/db/query/stable_hashes_test.clj @@ -6,33 +6,32 @@ (deftest stable-hashes-test (with-redefs [util/current-time-iso (constantly "1970-01-01T00:12:00.00000Z")] - (let [conn (test-utils/create-conn) - db0 @(fluree/create conn "stable-commit-id") + (let [conn (test-utils/create-conn) + _ @(fluree/create conn "stable-commit-id") context [test-utils/default-context {:ex "http://example.org/ns/"}] - db0 @(fluree/update - db0 - {"@context" context - "insert" - [{:id :ex/alice - :type :ex/User - :schema/name "Alice" - :schema/email "alice@flur.ee" - :schema/age 42} - {:id :ex/bob, - :type :ex/User, - :schema/name "Bob" - :schema/age 22} - {:id :ex/jane, - :type :ex/User, - :schema/name "Jane" - :schema/email "jane@flur.ee" - :schema/age 30}]}) - db1 @(fluree/commit! conn db0)] + db1 @(fluree/update! + conn "stable-commit-id" + {"@context" context + "insert" + [{:id :ex/alice + :type :ex/User + :schema/name "Alice" + :schema/email "alice@flur.ee" + :schema/age 42} + {:id :ex/bob + :type :ex/User + :schema/name "Bob" + :schema/age 22} + {:id :ex/jane + :type :ex/User + :schema/name "Jane" + :schema/email "jane@flur.ee" + :schema/age 30}]})] (testing "stable commit id" - (is (= "fluree:commit:sha256:bbdainpfs7v2pg2yj76uzpybdfdldvvt5idlbasisuhwlrxbiqhii" + (is (= "fluree:commit:sha256:be2l2fggrwhsqgd4hhug4l6co2v7nbucdwecinjhdkjwzzxw775q" (get-in db1 [:commit :id])))) (testing "stable commit address" - (is (= "fluree:memory://bdainpfs7v2pg2yj76uzpybdfdldvvt5idlbasisuhwlrxbiqhii" + (is (= "fluree:memory://e2l2fggrwhsqgd4hhug4l6co2v7nbucdwecinjhdkjwzzxw775q" (get-in db1 [:commit :address])))) (testing "stable db id" (is (= "fluree:db:sha256:btqomzs3uzs7dspzbs5ht4e7af7qrahnvomx4s4id7apr5jm7dxn" diff --git a/test/fluree/db/storage/s3_unit_test.clj b/test/fluree/db/storage/s3_unit_test.clj index 563aa0e01f..8758a38a1f 100644 --- a/test/fluree/db/storage/s3_unit_test.clj +++ b/test/fluree/db/storage/s3_unit_test.clj @@ -84,10 +84,10 @@ (deftest s3-path-encoding-test (testing "S3 path encoding handles special characters correctly" - (let [path-with-at "ns@v1/test-ledger@main.json" + (let [path-with-at "ns@v1/test-ledger/main.json" encoded (s3-storage/encode-s3-path path-with-at)] - (is (= "ns%40v1/test-ledger%40main.json" encoded) - "Should encode @ characters to %40")) + (is (= "ns%40v1/test-ledger/main.json" encoded) + "Should encode @ in directory name to %40")) (let [path-normal "bucket/prefix/file.json" encoded (s3-storage/encode-s3-path path-normal)] diff --git a/test/fluree/db_test.cljc b/test/fluree/db_test.cljc index ef4260a4c5..5af3282d6c 100644 --- a/test/fluree/db_test.cljc +++ b/test/fluree/db_test.cljc @@ -1,10 +1,10 @@ (ns fluree.db-test - (:require #?@(:clj [[clojure.core.async :as async] + (:require #?@(:clj [[babashka.fs :refer [with-temp-dir]] + [clojure.core.async :as async] [clojure.test :refer [deftest is testing]] - [fluree.db.did :as did] [fluree.db.async-db :as async-db] - [fluree.db.util.filesystem :as fs] - [babashka.fs :refer [with-temp-dir]]] + [fluree.db.did :as did] + [fluree.db.util.filesystem :as fs]] :cljs [[cljs.test :refer-macros [deftest is testing async]] [clojure.core.async :refer [go