Просмотр исходного кода

enhance: built-in properties are indexed by :db/ident

built-in-properties are identified by their :db/ident instead
of :block/name. This removes reliance on :block/name and allows
us to consistently use namespaces when identifying built-in properties

:visible was renamed to :public? and is now included in :block/schema to
allow for querying. Also added a couple more new graph tests and tweaked
CI for db dep
Gabriel Horner 1 год назад
Родитель
Сommit
eecb510ccb

+ 1 - 1
.github/workflows/db.yml

@@ -83,7 +83,7 @@ jobs:
           bb: ${{ env.BABASHKA_VERSION }}
 
       - name: Run clj-kondo lint
-        run: clojure -M:clj-kondo --parallel --lint src
+        run: clojure -M:clj-kondo --lint src test
 
       - name: Carve lint for unused vars
         run: bb lint:carve 2>/dev/null

+ 7 - 6
deps/db/src/logseq/db/frontend/class.cljs

@@ -1,12 +1,13 @@
 (ns logseq.db.frontend.class
   "Class related fns for DB graphs and frontend/datascript usage")
 
-;; TODO: disable name changes for those built-in page/class names and their properties names
 (def ^:large-vars/data-var built-in-classes
-  {:task {:original-name "Task"
-          :schema {:properties ["status" "priority" "scheduled"  "deadline"]}}
-   :card {:original-name "card"
-          ;; :schema {:property []}
-          }
+  "Map of built-in classes for db graphs with their :db/ident as keys"
+  {:logseq.class/task
+   {:original-name "Task"
+    :schema {:properties [:logseq.task/status :logseq.task/priority :logseq.task/scheduled :logseq.task/deadline]}}
+   :logseq.class/card {:original-name "card"
+                       ;; :schema {:property []}
+                       }
    ;; TODO: Add more classes such as :book, :paper, :movie, :music, :project
    })

+ 2 - 1
deps/db/src/logseq/db/frontend/malli_schema.cljs

@@ -158,7 +158,8 @@
        (concat
         [:map
          [:type (apply vector :enum (into db-property-type/internal-built-in-property-types
-                                          db-property-type/user-built-in-property-types))]]
+                                          db-property-type/user-built-in-property-types))]
+        [:public? {:optional true} :boolean]]
         property-common-schema-attrs
         property-type-schema-attrs))]]
     page-attrs

+ 148 - 170
deps/db/src/logseq/db/frontend/property.cljs

@@ -1,197 +1,175 @@
 (ns logseq.db.frontend.property
   "Property related fns for DB graphs and frontend/datascript usage"
-  (:require [clojure.set :as set]
-            [logseq.db.sqlite.util :as sqlite-util]
+  (:require [logseq.db.sqlite.util :as sqlite-util]
             [datascript.core :as d]
-            [logseq.common.util :as common-util]))
+            [logseq.common.util :as common-util]
+            [clojure.string :as string]))
 
 (def first-stage-properties
-  #{:built-in? :created-from-property})
+  #{:logseq.property/built-in? :logseq.property/created-from-property})
 
-(defn name->db-ident
-  "Converts a built-in property's keyword name to its :db/ident equivalent.
-  Legacy property names that had pseudo-namespacing are converted to their new
-  format e.g. :logseq.table.headers -> :logseq.property.table/headers"
-  [legacy-name]
-  ;; Migrate legacy names that have logseq.* style names but no namespace
-  (if-let [[_ additional-ns prop-name] (re-matches  #"logseq(.*)\.([^.]+)" (name legacy-name))]
-    (keyword (str "logseq.property" additional-ns) prop-name)
-    (keyword "logseq.property" (name legacy-name))))
-
-;; FIXME: no support for built-in-extended-properties
 (def ^:large-vars/data-var built-in-properties*
-  "Map of built in properties for db graphs. Each property has a config map with
-  the following keys:
-   * :schema - Property's schema. Required key
+  "Map of built in properties for db graphs with their :db/ident as keys.
+   Each property has a config map with the following keys:
+   * :schema - Property's schema. Required key. Has the following common keys:
+     * :type - Property type
+     * :cardinality - property cardinality. Default to one/single cardinality if not set
+     * :hide? - Boolean which hides property when set on a block
+     * :public? - Boolean which allows property to be used by user e.g. add and remove property to blocks/pages
    * :original-name - Property's :block/original-name
+   * :name - Property's :block/name as a keyword. If none given, one is derived from the db/ident
    * :attribute - Property keyword that is saved to a datascript attribute outside of :block/properties
-   * :visible - Boolean to indicate user can see and use this property
+   * :closed-values - Vec of closed-value maps for properties with choices. Map
+     has keys :value, :db-ident, :uuid and :icon
    * :db-ident - Keyword to set :db/ident and give property unique id in db"
-  {:alias {:original-name "Alias"
-           :attribute :block/alias
-           :visible true
-           :schema {:type :page
-                    :cardinality :many}}
-   :tags {:original-name "Tags"
-          :attribute :block/tags
-          :visible true
-          :schema {:type :page
-                   :cardinality :many
-                   :classes #{:logseq.class}}}
-   :pagetags {:original-name "pageTags"
-              :visible true
-              :schema {:type :page
-                       :cardinality :many}}
-   :background-color {:schema {:type :default :hide? true}}
-   :background-image {:schema {:type :default :hide? true}
-                      :visible true}
-   :heading {:schema {:type :any :hide? true}}      ; number (1-6) or boolean for auto heading
-   :created-from-block    {:schema {:type :uuid}}
-   :created-from-property {:schema {:type :uuid}}
-   :created-from-template {:schema {:type :uuid}}
-   :source-page-id        {:schema {:type :uuid}}
-   :built-in?             {:schema {:type :checkbox}}
-   :hide-properties?      {:schema {:type :checkbox}}
-   :query-table {:schema {:type :checkbox}}
+  {:logseq.property/alias {:original-name "Alias"
+                           :attribute :block/alias
+                           :schema {:type :page
+                                    :cardinality :many
+                                    :public? true}}
+   :logseq.property/tags {:original-name "Tags"
+                          :attribute :block/tags
+                          :schema {:type :page
+                                   :cardinality :many
+                                   :public? true
+                                   :classes #{:logseq.class}}}
+   :logseq.property/pagetags {:original-name "pageTags"
+                              :schema {:type :page
+                                       :public? true
+                                       :cardinality :many}}
+   :logseq.property/background-color {:schema {:type :default :hide? true}}
+   :logseq.property/background-image {:schema {:type :default :hide? true :public? true}}
+   ;; number (1-6) or boolean for auto heading
+   :logseq.property/heading {:schema {:type :any :hide? true}}
+   :logseq.property/created-from-block    {:schema {:type :uuid}}
+   :logseq.property/created-from-property {:schema {:type :uuid}}
+   :logseq.property/created-from-template {:schema {:type :uuid}}
+   :logseq.property/source-page-id        {:schema {:type :uuid}}
+   :logseq.property/built-in?             {:schema {:type :checkbox}}
+   :logseq.property/hide-properties?      {:schema {:type :checkbox}}
+   :logseq.property/query-table {:schema {:type :checkbox}}
    ;; query-properties is a coll of property uuids and keywords where keywords are special frontend keywords
-   :query-properties {:schema {:type :coll}}
+   :logseq.property/query-properties {:schema {:type :coll}}
    ;; query-sort-by is either a property uuid or a keyword where keyword is a special frontend keyword
-   :query-sort-by {:schema {:type :any}}
-   :query-sort-desc {:schema {:type :checkbox}}
-   :ls-type {:schema {:type :keyword}}
-   :hl-type {:schema {:type :keyword}}
-   :hl-page {:schema {:type :number}}
-   :hl-stamp {:schema {:type :number}}
-   :hl-color {:schema {:type :default}}
-   :logseq.macro-name {:schema {:type :default}}
-   :logseq.macro-arguments {:schema {:type :coll}}
-   :logseq.order-list-type {:schema {:type :default}}
-   :logseq.tldraw.page {:schema {:type :map}}
-   :logseq.tldraw.shape {:schema {:type :map}}
+   :logseq.property/query-sort-by {:schema {:type :any}}
+   :logseq.property/query-sort-desc {:schema {:type :checkbox}}
+   :logseq.property/ls-type {:schema {:type :keyword}}
+   :logseq.property/hl-type {:schema {:type :keyword}}
+   :logseq.property/hl-page {:schema {:type :number}}
+   :logseq.property/hl-stamp {:schema {:type :number}}
+   :logseq.property/hl-color {:schema {:type :default}}
+   :logseq.property/macro-name {:name :logseq.macro-name
+                                :schema {:type :default}}
+   :logseq.property/macro-arguments {:name :logseq.macro-arguments
+                                     :schema {:type :coll}}
+   :logseq.property/order-list-type {:name :logseq.order-list-type
+                                     :schema {:type :default}}
+   :logseq.property.tldraw/page {:name :logseq.tldraw.page
+                                 :schema {:type :map}}
+   :logseq.property.tldraw/shape {:name :logseq.tldraw.shape
+                                  :schema {:type :map}}
 
    ;; Task props
-   :status {:db-ident :logseq.task/status
-            :original-name "Status"
-            :schema
-            {:type :default}
-            :closed-values
-            (mapv (fn [[db-ident value icon]]
-                    {:db-ident db-ident
-                     :value value
-                     :uuid (random-uuid)
-                     :icon {:type :tabler-icon :id icon :name icon}})
-                  [[:logseq.task/status.backlog "Backlog" "Backlog"]
-                   [:logseq.task/status.todo "Todo" "Todo"]
-                   [:logseq.task/status.doing "Doing" "InProgress50"]
-                   [:logseq.task/status.in-review "In Review" "InReview"]
-                   [:logseq.task/status.done "Done" "Done"]
-                   [:logseq.task/status.canceled "Canceled" "Cancelled"]])
-            :visible true}
-   :priority {:db-ident :logseq.task/priority
-              :original-name "Priority"
-              :schema
-              {:type :default}
-              :closed-values
-              (mapv (fn [[db-ident value]]
-                      {:db-ident db-ident
-                       :value value
-                       :uuid (random-uuid)})
-                    [[:logseq.task/priority.urgent "Urgent"]
-                     [:logseq.task/priority.high "High"]
-                     [:logseq.task/priority.medium "Medium"]
-                     [:logseq.task/priority.low "Low"]])
-              :visible true}
-   :scheduled {:db-ident :logseq.task/scheduled
-               :original-name "Scheduled"
-               :schema {:type :date}
-               :visible true}
-   :deadline {:db-ident :logseq.task/deadline
-              :original-name "Deadline"
-              :schema {:type :date}
-              :visible true}
+   :logseq.task/status
+   {:original-name "Status"
+    :schema
+    {:type :default
+     :public? true}
+    :closed-values
+    (mapv (fn [[db-ident value icon]]
+            {:db-ident db-ident
+             :value value
+             :uuid (random-uuid)
+             :icon {:type :tabler-icon :id icon :name icon}})
+          [[:logseq.task/status.backlog "Backlog" "Backlog"]
+           [:logseq.task/status.todo "Todo" "Todo"]
+           [:logseq.task/status.doing "Doing" "InProgress50"]
+           [:logseq.task/status.in-review "In Review" "InReview"]
+           [:logseq.task/status.done "Done" "Done"]
+           [:logseq.task/status.canceled "Canceled" "Cancelled"]])}
+   :logseq.task/priority
+   {:original-name "Priority"
+    :schema
+    {:type :default
+     :public? true}
+    :closed-values
+    (mapv (fn [[db-ident value]]
+            {:db-ident db-ident
+             :value value
+             :uuid (random-uuid)})
+          [[:logseq.task/priority.urgent "Urgent"]
+           [:logseq.task/priority.high "High"]
+           [:logseq.task/priority.medium "Medium"]
+           [:logseq.task/priority.low "Low"]])}
+   :logseq.task/scheduled
+   {:original-name "Scheduled"
+    :schema {:type :date
+             :public? true}}
+   :logseq.task/deadline
+   {:original-name "Deadline"
+    :schema {:type :date
+             :public? true}}
 
    ;; TODO: Add more props :Assignee, :Estimate, :Cycle, :Project
 
    ;; color props
-   :logseq.color {:schema
-                  {:type :default :hide? true}
-                  :closed-values
-                  (mapv #(hash-map :db-ident (keyword "logseq.property" (str "color." %))
-                                   :value %
-                                   :uuid (random-uuid))
-                        ;; Stringified version of frontend.colors/COLORS. Too basic to couple
-                        ["tomato" "red" "crimson" "pink" "plum" "purple" "violet" "indigo" "blue" "cyan" "teal" "green" "grass" "orange" "brown"])
-                  :visible true}
+   :logseq.property/color
+   {:name :logseq.color
+    :schema
+    {:type :default :hide? true :public? true}
+    :closed-values
+    (mapv #(hash-map :db-ident (keyword "logseq.property" (str "color." %))
+                     :value %
+                     :uuid (random-uuid))
+          ;; Stringified version of frontend.colors/COLORS. Too basic to couple
+          ["tomato" "red" "crimson" "pink" "plum" "purple" "violet" "indigo" "blue" "cyan" "teal" "green" "grass" "orange" "brown"])}
    ;; table-v2 props
-   :logseq.table.version {:schema {:type :number :hide? true}
-                          :visible true}
-   :logseq.table.compact {:schema {:type :checkbox :hide? true}
-                          :visible true}
-   :logseq.table.headers {:schema
-                          {:type :default :hide? true}
-                          :closed-values
-                          (mapv #(hash-map :db-ident (keyword "logseq.property.table" (str "headers." %))
-                                           :value %
-                                           :uuid (random-uuid))
-                                ["uppercase" "capitalize" "capitalize-first" "lowercase"])
-                          :visible true}
-   :logseq.table.hover {:schema
-                        {:type :default :hide? true}
-                        :closed-values
-                        (mapv #(hash-map :db-ident (keyword "logseq.property.table" (str "hover." %))
-                                         :value %
-                                         :uuid (random-uuid))
-                              ["row" "col" "both" "none"])
-                        :visible true}
-   :logseq.table.borders {:schema {:type :checkbox :hide? true}
-                          :visible true}
-   :logseq.table.stripes {:schema {:type :checkbox :hide? true}
-                          :visible true}
-   :logseq.table.max-width {:schema {:type :number :hide? true}
-                            :visible true}
-
-   :icon {:original-name "Icon"
-          :schema {:type :map}}
-   :public {:schema {:type :checkbox :hide? true}
-            :visible true}
-   :filters {:schema {:type :map}}
-   :exclude-from-graph-view {:schema {:type :checkbox :hide? true}
-                             :visible true}})
+   :logseq.property.table/version {:name :logseq.table.version
+                                   :schema {:type :number :hide? true :public? true}}
+   :logseq.property.table/compact {:name :logseq.table.compact
+                                   :schema {:type :checkbox :hide? true :public? true}}
+   :logseq.property.table/headers
+   {:name :logseq.table.headers
+    :schema
+    {:type :default :hide? true :public? true}
+    :closed-values
+    (mapv #(hash-map :db-ident (keyword "logseq.property.table" (str "headers." %))
+                     :value %
+                     :uuid (random-uuid))
+          ["uppercase" "capitalize" "capitalize-first" "lowercase"])}
+   :logseq.property.table/hover
+   {:name :logseq.table.hover
+    :schema
+    {:type :default :hide? true :public? true}
+    :closed-values
+    (mapv #(hash-map :db-ident (keyword "logseq.property.table" (str "hover." %))
+                     :value %
+                     :uuid (random-uuid))
+          ["row" "col" "both" "none"])}
+   :logseq.property.table/borders {:name :logseq.table.borders
+                                   :schema {:type :checkbox :hide? true :public? true}}
+   :logseq.property.table/stripes {:name :logseq.table.stripes
+                                   :schema {:type :checkbox :hide? true :public? true}}
+   :logseq.property.table/max-width {:name :logseq.table.max-width
+                                     :schema {:type :number :hide? true :public? true}}
+
+   :logseq.property/icon {:original-name "Icon"
+                          :schema {:type :map}}
+   :logseq.property/public {:schema {:type :checkbox :hide? true}}
+   :logseq.property/filters {:schema {:type :map}}
+   :logseq.property/exclude-from-graph-view {:schema {:type :checkbox :hide? true :public? true}}})
 
 (def built-in-properties
   (->> built-in-properties*
        (map (fn [[k v]]
-              (assert (keyword? k))
-              [k (assoc v
-                        :db-ident
-                        (get v :db-ident (name->db-ident k)))]))
-       (into {})))
-
-(def built-in-properties-by-ident
-  "built-in properties with keys being :db/ident
-   TODO: Replace built-in-properties with this var"
-  (->> built-in-properties
-       (map (fn [[k v]]
-              (assert (keyword? (:db-ident v)))
-              [(:db-ident v)
-               (-> v
-                   (dissoc :db-ident)
-                   (assoc :name k))]))
+              (assert (and (keyword? k) (namespace k)))
+              [k
+               ;; All built-ins must have a :name
+               (if (:name v)
+                 v
+                 (assoc v :name (keyword (string/lower-case (name k)))))]))
        (into {})))
 
-(def visible-built-in-properties
-  "These are built-in properties that users can see and use"
-  (set (keep (fn [[k v]] (when (:visible v) k)) built-in-properties)))
-
-(defonce built-in-properties-keys
-  (set (keys built-in-properties)))
-
-(def hidden-built-in-properties
-  (set/difference built-in-properties-keys visible-built-in-properties))
-
-(defonce built-in-properties-keys-str
-  (set (map name (keys built-in-properties))))
-
 (defn valid-property-name?
   [s]
   {:pre [(string? s)]}
@@ -224,7 +202,7 @@
   [repo db db-ident]
   (if (sqlite-util/db-based-graph? repo)
     (:block/uuid (d/entity db db-ident))
-    (get-in built-in-properties-by-ident [db-ident :name])))
+    (get-in built-in-properties [db-ident :name])))
 
 (defn get-property
   "Get a property given its unsanitized name"

+ 31 - 32
deps/db/src/logseq/db/sqlite/create_graph.cljs

@@ -13,26 +13,26 @@
 (defn- build-initial-properties
   [db]
   (let [;; Some uuids need to be pre-defined since they are referenced by other properties
-        default-property-uuids {:icon (d/squuid)}]
+        default-property-uuids {:logseq.property/icon (d/squuid)}]
     (mapcat
-     (fn [[k-keyword {:keys [schema original-name closed-values db-ident]}]]
-       (let [k-name (name k-keyword)
-             id (if (contains? db-property/first-stage-properties k-keyword)
+     (fn [[db-ident {:keys [schema original-name closed-values] :as m}]]
+       (let [id (if (contains? db-property/first-stage-properties db-ident)
                   (let [id (:block/uuid (d/entity db db-ident))]
                     (assert (uuid? id) "First stage properties are not created yet")
                     id)
                   (d/squuid))
+             prop-name (or original-name (name (:name m)))
              blocks (if closed-values
                       (db-property-util/build-closed-values
                        db
-                       (or original-name k-name)
+                       prop-name
                        {:block/schema schema :block/uuid id :closed-values closed-values}
-                       {:icon-id (get default-property-uuids :icon)
+                       {:icon-id (get default-property-uuids :logseq.property/icon)
                         :db-ident db-ident})
                       [(sqlite-util/build-new-property
-                        (or original-name k-name)
+                        prop-name
                         schema
-                        (get default-property-uuids k-keyword id)
+                        (get default-property-uuids db-ident id)
                         {:db-ident db-ident})])]
          (update blocks 0 #(default-db/mark-block-as-built-in db %))))
      db-property/built-in-properties)))
@@ -47,9 +47,9 @@
 (defn build-db-initial-data
   [db* config-content]
   (let [db (d/db-with db*
-                      (map (fn [p]
-                             {:db/ident (db-property/name->db-ident p)
-                              :block/name (name p)
+                      (map (fn [ident]
+                             {:db/ident ident
+                              :block/name (name ident)
                               :block/uuid (random-uuid)}) db-property/first-stage-properties))
         initial-data [(kv :db/type "db")
                       (kv :schema/version db-schema/version)]
@@ -68,27 +68,26 @@
         default-pages (->> (ldb/build-pages-tx (map default-db/page-title->block ["Contents"]))
                            (map #(default-db/mark-block-as-built-in db %)))
         default-properties (build-initial-properties db)
-        name->properties (zipmap
-                          (map :block/name default-properties)
-                          default-properties)
+        db-ident->properties (zipmap
+                              (map :db/ident default-properties)
+                              default-properties)
         default-classes (map
-                         (fn [[k-keyword {:keys [schema original-name]}]]
-                           (let [k-name (name k-keyword)]
-                             (default-db/mark-block-as-built-in
-                              db
-                              (sqlite-util/build-new-class
-                               (let [properties (mapv
-                                                 (fn [property-name]
-                                                   (let [id (:block/uuid (get name->properties property-name))]
-                                                     (assert id (str "Built-in property " property-name " is not defined yet"))
-                                                     id))
-                                                 (:properties schema))]
-                                 (cond->
-                                  {:block/original-name (or original-name k-name)
-                                   :block/name (common-util/page-name-sanity-lc k-name)
-                                   :db/ident (keyword "logseq.class" k-name)
-                                   :block/uuid (d/squuid)}
-                                   (seq properties)
-                                   (assoc-in [:block/schema :properties] properties)))))))
+                         (fn [[db-ident {:keys [schema original-name]}]]
+                           (default-db/mark-block-as-built-in
+                            db
+                            (sqlite-util/build-new-class
+                             (let [properties (mapv
+                                               (fn [db-ident]
+                                                 (let [id (:block/uuid (get db-ident->properties db-ident))]
+                                                   (assert id (str "Built-in property " db-ident " is not defined yet"))
+                                                   id))
+                                               (:properties schema))]
+                               (cond->
+                                {:block/original-name (or original-name (name db-ident))
+                                 :block/name (common-util/page-name-sanity-lc (name db-ident))
+                                 :db/ident db-ident
+                                 :block/uuid (d/squuid)}
+                                 (seq properties)
+                                 (assoc-in [:block/schema :properties] properties))))))
                          db-class/built-in-classes)]
     (vec (concat initial-data initial-files default-pages default-classes default-properties))))

+ 0 - 1
deps/db/test/logseq/db/sqlite/common_db_test.cljs

@@ -4,7 +4,6 @@
             ["path" :as node-path]
             [datascript.core :as d]
             [logseq.db.sqlite.common-db :as sqlite-common-db]
-            [logseq.db.frontend.schema :as db-schema]
             [logseq.common.util.date-time :as date-time-util]
             [logseq.db.sqlite.db :as sqlite-db]
             [clojure.string :as string]))

+ 27 - 2
deps/db/test/logseq/db/sqlite/create_graph_test.cljs

@@ -5,9 +5,10 @@
             [datascript.core :as d]
             [logseq.db.frontend.schema :as db-schema]
             [logseq.db.sqlite.create-graph :as sqlite-create-graph]
-            [logseq.db.frontend.validate :as db-validate]))
+            [logseq.db.frontend.validate :as db-validate]
+            [logseq.db :as ldb]))
 
-(deftest build-db-initial-data
+(deftest new-graph-db-idents
   (testing "a new graph follows :db/ident conventions for"
     (let [conn (d/create-conn db-schema/schema-for-db-based-graph)
           _ (d/transact! conn (sqlite-create-graph/build-db-initial-data @conn "{}"))
@@ -40,6 +41,30 @@
                  (set/difference closed-value-properties (set default-idents)))
               "All closed values start with a prefix that is a property name"))))))
 
+(deftest new-graph-marks-built-ins
+  (let [conn (d/create-conn db-schema/schema-for-db-based-graph)
+        _ (d/transact! conn (sqlite-create-graph/build-db-initial-data @conn "{}"))
+        idents (->> (d/q '[:find [(pull ?b [:db/ident :block/properties]) ...]
+                           :where [?b :db/ident]]
+                         @conn)
+                    ;; only kv's don't have built-in property
+                    (remove #(= "logseq.kv" (namespace (:db/ident %)))))]
+    (is (= []
+           (remove #(ldb/built-in? @conn %) idents))
+        "All entities with :db/ident have built-in property (except for kv idents)")))
+
+(deftest new-graph-creates-class
+  (let [conn (d/create-conn db-schema/schema-for-db-based-graph)
+        _ (d/transact! conn (sqlite-create-graph/build-db-initial-data @conn "{}"))
+        task (d/entity @conn :logseq.class/task)]
+    (is (contains? (:block/type task) "class")
+        "Task class has correct type")
+    (is (= 4 (count (get-in task [:block/schema :properties])))
+        "Has correct number of task properties")
+    (is (every? #(contains? (:block/type (d/entity @conn [:block/uuid %])) "property")
+                (get-in task [:schema :properties]))
+        "Each task property has correct type")))
+
 (deftest new-graph-is-valid
   (let [conn (d/create-conn db-schema/schema-for-db-based-graph)
         _ (d/transact! conn (sqlite-create-graph/build-db-initial-data @conn "{}"))

+ 14 - 6
deps/graph-parser/src/logseq/graph_parser/exporter.cljs

@@ -254,6 +254,14 @@
       (throw (ex-info (str "No uuid found for page " (pr-str k))
                       {:page k}))))
 
+(def built-in-property-names
+  "Set of all built-in property names as keywords. Using in-memory property
+  names because these are legacy names already in a user's file graph"
+  (->> db-property/built-in-properties
+       vals
+       (map :name)
+       set))
+
 (defn- update-properties
   "Updates block property names and values"
   [props db page-names-to-uuids
@@ -266,7 +274,7 @@
                                                 {:page k}))))
                           (fn prop-name->uuid [k]
                             (cached-prop-name->uuid db page-names-to-uuids k)))
-        user-properties (apply dissoc props db-property/built-in-properties-keys)]
+        user-properties (apply dissoc props built-in-property-names)]
     (when (seq user-properties)
       (swap! (:block-properties-text-values import-state)
              assoc
@@ -277,7 +285,7 @@
     (if (contains? props :template)
       {}
       (-> (update-built-in-property-values
-           (select-keys props db-property/built-in-properties-keys)
+           (select-keys props built-in-property-names)
            db
            (:ignored-properties import-state)
            (select-keys block [:block/name :block/content]))
@@ -302,7 +310,7 @@
                                property-classes)]
     (->> (apply dissoc properties dissoced-props)
          (keep (fn [[prop val]]
-                 (if (not (contains? db-property/built-in-properties-keys prop))
+                 (if (not (contains? built-in-property-names prop))
                   ;; only update user properties
                    (if (string? val)
                     ;; Ignore blank values as they were usually generated by templates
@@ -330,7 +338,7 @@
               properties-to-infer (if (:template properties')
                                     ;; Ignore template properties as they don't consistently have representative property values
                                     {}
-                                    (apply dissoc properties' db-property/built-in-properties-keys))
+                                    (apply dissoc properties' built-in-property-names))
               property-changes
               (->> properties-to-infer
                    (keep (fn [[prop val]]
@@ -562,7 +570,7 @@
     :tag-classes (set (map string/lower-case (:tag-classes user-options)))
     :property-classes (set/difference
                        (set (map (comp keyword string/lower-case) (:property-classes user-options)))
-                       db-property/built-in-properties-keys)}))
+                       built-in-property-names)}))
 
 (defn add-file-to-db-graph
   "Parse file and save parsed data to the given db graph. Options available:
@@ -737,7 +745,7 @@
                     [(get ?bp ?prop-uuid) ?_v]]
                   @conn
                   (set (map :block/name user-classes)))
-             (remove #(db-property/built-in-properties-keys-str (second %)))
+             (remove #(ldb/built-in? @conn (d/entity @conn [:block/name (second %)])))
              (reduce (fn [acc [class-id _prop-name prop-uuid]]
                        (update acc class-id (fnil conj #{}) prop-uuid))
                      {}))

+ 2 - 2
src/main/frontend/components/page_menu.cljs

@@ -20,7 +20,7 @@
             [frontend.handler.file-sync :as file-sync-handler]
             [logseq.common.path :as path]
             [frontend.handler.property.util :as pu]
-            [logseq.db.frontend.property :as db-property]))
+            [logseq.db :as ldb]))
 
 (defn- delete-page!
   [page-name]
@@ -71,7 +71,7 @@
                                     (file-sync-handler/current-graph-sync-on?)
                                     (file-sync-handler/get-current-graph-uuid))
           built-in-property? (and (contains? (:block/type page) "property")
-                                  (contains? db-property/built-in-properties-keys-str page-name))
+                                  (ldb/built-in? (db/get-db repo) page))
           db-based? (config/db-based-graph? repo)]
       (when (and page (not block?))
         (->>

+ 18 - 20
src/main/frontend/components/property.cljs

@@ -128,13 +128,13 @@
 
 (rum/defc schema-type <
   shortcut/disable-all-shortcuts
-  [property {:keys [*property-name *property-schema built-in-property? disabled?
+  [property {:keys [*property-name *property-schema built-in? disabled?
                     show-type-change-hints? in-block-container? block *show-new-property-config?
                     default-open?]}]
   (let [property-name (or (and *property-name @*property-name) (:block/original-name property))
         property-schema (or (and *property-schema @*property-schema) (:block/schema property))
         schema-types (->> (concat db-property-type/user-built-in-property-types
-                                  (when built-in-property?
+                                  (when built-in?
                                     db-property-type/internal-built-in-property-types))
                           (map (fn [type]
                                  {:label (property-type-label type)
@@ -223,7 +223,6 @@
     (when-not (= :loading values)
       (let [*property-name (::property-name state)
             *property-schema (::property-schema state)
-            built-in-property? (contains? db-property/built-in-properties-keys-str (:block/original-name property))
             property (db/sub-block (:db/id property))
             built-in? (ldb/built-in? (db/get-db) property)
             disabled? (or built-in? config/publishing?)
@@ -279,7 +278,7 @@
                         (svg/help-circle))]
              (schema-type property {:*property-name *property-name
                                     :*property-schema *property-schema
-                                    :built-in-property? built-in-property?
+                                    :built-in? built-in?
                                     :disabled? disabled?
                                     :show-type-change-hints? true}))]
 
@@ -394,23 +393,24 @@
   [entity property-name {:keys [class-schema? page-configure?]}]
   (let [repo (state/get-current-repo)]
     ;; existing property selected or entered
-    (if-let [_property (get-property-from-db property-name)]
-      (if (contains? db-property/hidden-built-in-properties (keyword property-name))
-        (do (notification/show! "This is a built-in property that can't be used." :error)
+    (if-let [property (get-property-from-db property-name)]
+      (if (and (not (get-in property [:block/schema :public?]))
+               (ldb/built-in? (db/get-db repo) property))
+        (do (notification/show! "This is a private built-in property that can't be used." :error)
             (pv/exit-edit-property))
         ;; Both conditions necessary so that a class can add its own page properties
         (when (and (contains? (:block/type entity) "class") class-schema?)
           (pv/<add-property! entity property-name "" {:class-schema? class-schema?
                                                      ;; Only enter property names from sub-modal as inputting
                                                      ;; property values is buggy in sub-modal
-                                                     :exit-edit? page-configure?})))
+                                                      :exit-edit? page-configure?})))
       ;; new property entered
       (if (db-property/valid-property-name? property-name)
         (if (and (contains? (:block/type entity) "class") page-configure?)
           (pv/<add-property! entity property-name "" {:class-schema? class-schema? :exit-edit? page-configure?})
           (p/do!
-            (db-property-handler/upsert-property! repo property-name {} {})
-            true))
+           (db-property-handler/upsert-property! repo property-name {} {})
+           true))
         (do (notification/show! "This is an invalid property name. A property name cannot start with page reference characters '#' or '[['." :error)
             (pv/exit-edit-property))))))
 
@@ -449,14 +449,10 @@
                                (map #(:block/original-name (db/entity [:block/uuid %])))
                                (remove nil?)
                                (set))
-        existing-tag-alias (reduce (fn [acc prop]
-                                     (if (seq (get entity (get-in db-property/built-in-properties [prop :attribute])))
-                                       (if-let [name (get-in db-property/built-in-properties [prop :original-name])]
-                                         (conj acc name)
-                                         acc)
-                                       acc))
-                                   #{}
-                                   [:tags :alias])
+        existing-tag-alias (->> [:logseq.property/tags :logseq.property/alias]
+                                (map db-property/built-in-properties)
+                                (keep #(when (get entity (:attribute %)) (:original-name %)))
+                                set)
         exclude-properties* (set/union entity-properties existing-tag-alias)
         exclude-properties (set/union exclude-properties* (set (map string/lower-case exclude-properties*)))]
     [:div.ls-property-input.flex.flex-1.flex-row.items-center.flex-wrap.gap-1
@@ -720,11 +716,13 @@
         alias (set (map :block/uuid (:block/alias block)))
         alias-properties (when (seq alias)
                            [[(db-pu/get-built-in-property-uuid :logseq.property/alias) alias]])
+        db (db/get-db (state/get-current-repo))
         remove-built-in-properties (fn [properties]
                                      (remove (fn [x]
                                                (let [id (if (uuid? x) x (first x))]
-                                                 (when (uuid? id)
-                                                   (contains? db-property/hidden-built-in-properties (keyword (:block/name (db/entity [:block/uuid id])))))))
+                                                 (when-let [ent (and (uuid? id) (db/entity [:block/uuid id]))]
+                                                   (and (not (get-in ent [:block/schema :public?]))
+                                                        (ldb/built-in? db ent)))))
                                              properties))
         {:keys [classes all-classes classes-properties]} (db-property-handler/get-block-classes-properties (:db/id block))
         one-class? (= 1 (count classes))

+ 1 - 1
src/main/frontend/components/query_table.cljs

@@ -113,7 +113,7 @@
                             ;; TODO: Support additional hidden properties e.g. from user config
                             ;; or gp-property/built-in-extended properties
                             (set (map #(db-pu/get-built-in-property-uuid repo %)
-                                      (keys db-property/built-in-properties-by-ident)))
+                                      (keys db-property/built-in-properties)))
                             (conj (file-property-handler/built-in-properties) :template))
         prop-keys* (->> (distinct (mapcat keys (map :block/properties result)))
                         (remove hidden-properties))

+ 8 - 3
src/main/frontend/db/async.cljs

@@ -50,14 +50,19 @@
       (get templates name))))
 
 (defn- <db-based-get-all-properties
-  "Return seq of property names. :block/type could be one of [property, class]."
+  "Return seq of all property names except for private built-in properties."
   [graph]
   (p/let [result (<q graph
-                     '[:find [(pull ?e [:block/original-name]) ...]
+                     '[:find [(pull ?e [:block/original-name :block/schema :db/ident]) ...]
                        :where
                        [?e :block/type "property"]
                        [?e :block/original-name]])]
-    (map :block/original-name result)))
+    (->> result
+         ;; remove private built-in properties
+         (remove #(and (:db/ident %)
+                       (string/starts-with? (namespace (:db/ident %)) "logseq.")
+                       (not (get-in % [:block/schema :public?]))))
+         (map :block/original-name))))
 
 (defn <get-all-properties
   "Returns a seq of property name strings"

+ 12 - 3
src/main/frontend/format/block.cljs

@@ -16,15 +16,24 @@
             [logseq.db.frontend.property :as db-property]
             [frontend.format.mldoc :as mldoc]))
 
+(def built-in-property-names-to-idents
+  "This maps built-in properties names to idents. Only use
+   with legacy internals where names are hardcoded"
+  (into {}
+        (map (fn [[k v]]
+               [(:name v) k])
+             db-property/built-in-properties)))
+
 (defn- update-extracted-block-properties
   "Updates DB graph blocks to ensure that built-in properties are using uuids
   for property ids"
   [blocks]
   (let [repo (state/get-current-repo)
         update-properties (fn [props]
-                            (update-keys props #(if (contains? db-property/built-in-properties-keys %)
-                                                  (db-pu/get-built-in-property-uuid repo (get-in db-property/built-in-properties [% :db-ident]))
-                                                  %)))]
+                            (update-keys props
+                                         #(if-let [ident (built-in-property-names-to-idents %)]
+                                            (db-pu/get-built-in-property-uuid repo ident)
+                                            %)))]
     (if (config/db-based-graph? repo)
      (->> blocks
           (map (fn [b]

+ 9 - 9
src/main/frontend/handler/page.cljs

@@ -26,7 +26,6 @@
             [goog.functions :refer [debounce]]
             [goog.object :as gobj]
             [lambdaisland.glogi :as log]
-            [logseq.db.frontend.property :as db-property]
             [logseq.common.config :as common-config]
             [logseq.common.util :as common-util]
             [logseq.common.util.page-ref :as page-ref]
@@ -228,14 +227,15 @@
 
 (defn get-all-pages
   [repo]
-  (->> (db/get-all-pages repo)
-       (remove (fn [p]
-                 (let [name (:block/name p)]
-                   (or (util/uuid-string? name)
-                       (common-config/draw? name)
-                       (db/built-in-pages-names (string/upper-case name))
-                       (db-property/built-in-properties-keys-str name)))))
-       (common-handler/fix-pages-timestamps)))
+  (let [db (conn/get-db repo)]
+    (->> (db/get-all-pages repo)
+        (remove (fn [p]
+                  (let [name (:block/name p)]
+                    (or (util/uuid-string? name)
+                        (common-config/draw? name)
+                        (db/built-in-pages-names (string/upper-case name))
+                        (and (contains? (set (:block/type p)) "property") (ldb/built-in? db p))))))
+        (common-handler/fix-pages-timestamps))))
 
 (defn get-filters
   [page-name]

+ 5 - 7
src/main/frontend/search.cljs

@@ -12,7 +12,6 @@
             [logseq.common.config :as common-config]
             [frontend.db.async :as db-async]
             [frontend.config :as config]
-            [logseq.db.frontend.property :as db-property]
             [frontend.handler.file-based.property.util :as property-util]
             [cljs-bean.core :as bean]
             [frontend.db :as db]
@@ -73,12 +72,11 @@
   []
   (when-let [repo (state/get-current-repo)]
     (let [hidden-props (if (config/db-based-graph? repo)
-                        (set (map #(or (get-in db-property/built-in-properties [% :original-name])
-                                       (name %))
-                                  db-property/hidden-built-in-properties))
-                        (set (map name (property-util/hidden-properties))))]
-     (p/let [properties (db-async/<get-all-properties)]
-       (remove hidden-props properties)))))
+                         ;; no-op since already removed
+                         (constantly false)
+                         (set (map name (property-util/hidden-properties))))]
+      (p/let [properties (db-async/<get-all-properties)]
+        (remove hidden-props properties)))))
 
 (defn property-search
   ([q]