validate_client_db.cljs 4.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. (ns validate-client-db
  2. "Script that validates the datascript db of a DB graph
  3. NOTE: This script is also used in CI to confirm our db's schema is up to date"
  4. (:require [logseq.db.sqlite.db :as sqlite-db]
  5. [logseq.db.frontend.malli-schema :as db-malli-schema]
  6. [logseq.db.frontend.validate :as db-validate]
  7. [logseq.db.frontend.property :as db-property]
  8. [datascript.core :as d]
  9. [clojure.string :as string]
  10. [nbb.core :as nbb]
  11. [malli.core :as m]
  12. [babashka.cli :as cli]
  13. ["path" :as node-path]
  14. ["os" :as os]
  15. [cljs.pprint :as pprint]))
  16. (defn validate-client-db
  17. "Validate datascript db as a vec of entity maps"
  18. [db ent-maps* {:keys [verbose group-errors closed-maps]}]
  19. (let [ent-maps ent-maps*
  20. ;; TODO: Fix
  21. ;; ent-maps (db-malli-schema/update-properties-in-ents ent-maps*)
  22. schema (db-validate/update-schema db-malli-schema/DB db {:closed-schema? closed-maps})]
  23. (if-let [errors (->> ent-maps
  24. (m/explain schema)
  25. :errors)]
  26. (do
  27. (if group-errors
  28. (let [ent-errors (db-validate/group-errors-by-entity db ent-maps errors)]
  29. (println "Found" (count ent-errors) "entities in errors:")
  30. (if verbose
  31. (pprint/pprint ent-errors)
  32. (pprint/pprint (map :entity ent-errors))))
  33. (do
  34. (println "Found" (count errors) "errors:")
  35. (if verbose
  36. (pprint/pprint
  37. (map #(assoc %
  38. :entity (get ent-maps (-> % :in first))
  39. :schema (m/form (:schema %)))
  40. errors))
  41. (pprint/pprint errors))))
  42. (js/process.exit 1))
  43. (println "Valid!"))))
  44. (def spec
  45. "Options spec"
  46. {:help {:alias :h
  47. :desc "Print help"}
  48. :verbose {:alias :v
  49. :desc "Print more info"}
  50. :closed-maps {:alias :c
  51. :desc "Validate maps marked with closed as :closed"}
  52. :group-errors {:alias :g
  53. :desc "Groups errors by their entity id"}})
  54. (defn- validate-graph [graph-dir options]
  55. (let [[dir db-name] (if (string/includes? graph-dir "/")
  56. (let [graph-dir'
  57. (node-path/join (or js/process.env.ORIGINAL_PWD ".") graph-dir)]
  58. ((juxt node-path/dirname node-path/basename) graph-dir'))
  59. [(node-path/join (os/homedir) "logseq" "graphs") graph-dir])
  60. conn (try (sqlite-db/open-db! dir db-name)
  61. (catch :default e
  62. (println "Error: For graph" (str (pr-str graph-dir) ":") (str e))
  63. (js/process.exit 1)))
  64. datoms (d/datoms @conn :eavt)
  65. ent-maps (db-malli-schema/datoms->entities datoms)]
  66. (println "Read graph" (str db-name " with " (count datoms) " datoms, "
  67. (count ent-maps) " entities, "
  68. (count (filter :block/name ent-maps)) " pages, "
  69. (count (filter :block/content ent-maps)) " blocks, "
  70. (count (filter #(contains? (:block/type %) "class") ent-maps)) " classes, "
  71. (count (filter #(seq (:block/tags %)) ent-maps)) " objects, "
  72. (count (filter #(contains? (:block/type %) "property") ent-maps)) " properties and "
  73. (count (filter :property/pair-property ent-maps)) " property pairs"))
  74. (validate-client-db @conn ent-maps options)))
  75. (defn -main [argv]
  76. (let [{:keys [args opts]} (cli/parse-args argv {:spec spec})
  77. _ (when (or (empty? args) (:help opts))
  78. (println (str "Usage: $0 GRAPH-NAME [& ADDITIONAL-GRAPHS] [OPTIONS]\nOptions:\n"
  79. (cli/format-opts {:spec spec})))
  80. (js/process.exit 1))]
  81. (doseq [graph-dir args]
  82. (validate-graph graph-dir opts))))
  83. (when (= nbb/*file* (:file (meta #'-main)))
  84. (-main *command-line-args*))