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

refactor: remove [:block/schema :values]

Some changes:
1. use :block/closed-value-property instead to record which property
this value entity belongs to.
2. use :block/content instead of [:block/schema :value].
3. :page and :date have been removed from closed-value-property-types
because there could be a page/date that's a closed value for multiple
properties, we have no idea what's the `:block/order` for a specific
property.
Tienson Qin 1 год назад
Родитель
Сommit
1cb0896e3b

+ 19 - 14
deps/db/src/logseq/db.cljs

@@ -128,17 +128,28 @@
   [db page-id]
   (count (d/datoms db :avet :block/page page-id)))
 
+(defn- get-block-children-or-property-children
+  [block parent]
+  (let [from-property (:logseq.property/created-from-property block)
+        closed-property (:block/closed-value-property block)]
+    (sort-by-order (cond
+                     closed-property
+                     (:property/closed-values closed-property)
+
+                     from-property
+                     (filter (fn [e]
+                               (= (:db/id (:logseq.property/created-from-property e))
+                                  (:db/id from-property)))
+                             (:block/_raw-parent parent))
+
+                     :else
+                     (:block/_parent parent)))))
+
 (defn get-right-sibling
   [block]
   (assert (or (de/entity? block) (nil? block)))
   (when-let [parent (:block/parent block)]
-    (let [from-property (:logseq.property/created-from-property block)
-          children (sort-by-order (if from-property
-                                    (filter (fn [e]
-                                              (= (:db/id (:logseq.property/created-from-property e))
-                                                 (:db/id from-property)))
-                                            (:block/_raw-parent parent))
-                                    (:block/_parent parent)))
+    (let [children (get-block-children-or-property-children block parent)
           right (some (fn [child] (when (> (compare (:block/order child) (:block/order block)) 0) child)) children)]
       (when (not= (:db/id right) (:db/id block))
         right))))
@@ -147,13 +158,7 @@
   [block]
   (assert (or (de/entity? block) (nil? block)))
   (when-let [parent (:block/parent block)]
-    (let [from-property (:logseq.property/created-from-property block)
-          children (reverse (sort-by-order (if from-property
-                                             (filter (fn [e]
-                                                       (= (:db/id (:logseq.property/created-from-property e))
-                                                          (:db/id from-property)))
-                                                     (:block/_raw-parent parent))
-                                             (:block/_parent parent))))
+    (let [children (reverse (get-block-children-or-property-children block parent))
           left (some (fn [child] (when (< (compare (:block/order child) (:block/order block)) 0) child)) children)]
       (when (not= (:db/id left) (:db/id block))
         left))))

+ 10 - 5
deps/db/src/logseq/db/frontend/entity_plus.cljc

@@ -37,12 +37,13 @@
      :block/content
      (or
       (get (.-kv e) k)
-      (let [result (lookup-entity e k default-value)
-            refs (:block/refs e)
-            tags (:block/tags e)]
+      (let [result (lookup-entity e k default-value)]
         (or
-         (when (string? result)
-           (db-content/special-id-ref->page-ref result (distinct (concat refs tags))))
+         (if (string? result)
+           (let [refs (:block/refs e)
+                 tags (:block/tags e)]
+             (db-content/special-id-ref->page-ref result (distinct (concat refs tags))))
+           result)
          default-value)))
 
      :block/_parent
@@ -53,6 +54,10 @@
      :block/_raw-parent
      (lookup-entity e :block/_parent default-value)
 
+     :property/closed-values
+     (->> (lookup-entity e :block/_closed-value-property default-value)
+          (sort-by :block/order))
+
      (or (get (.-kv e) k)
          (lookup-entity e k default-value)))))
 

+ 3 - 3
deps/db/src/logseq/db/frontend/malli_schema.cljs

@@ -71,10 +71,10 @@
         validate-fn'' (if (and (db-property-type/closed-value-property-types (:type schema))
                                ;; new closed values aren't associated with the property yet
                                (not new-closed-value?)
-                               (seq (:values schema)))
+                               (seq (:property/closed-values property)))
                         (fn closed-value-valid? [val]
                           (and (validate-fn' val)
-                               (contains? (set (:values schema))
+                               (contains? (set (map :block/uuid (:property/closed-values property)))
                                           (:block/uuid (d/entity db val)))))
                         validate-fn')]
     (if (= (:cardinality schema) :many)
@@ -321,7 +321,7 @@
   [[:block/content :string]
    [:block/parent :int]
    [:block/order :string]
-   [:property/schema.value {:optional true} :any]
+   [:block/closed-value-property {:optional true} [:set :int]]
    ;; refs
    [:block/page :int]
    [:block/path-refs {:optional true} [:set :int]]

+ 48 - 16
deps/db/src/logseq/db/frontend/order.cljs

@@ -6,35 +6,67 @@
 (defonce *max-key (atom nil))
 
 (defn reset-max-key!
-  [key]
-  (when (and key (or (nil? @*max-key)
-                     (> (compare key @*max-key) 0)))
-    (reset! *max-key key)))
+  ([key]
+   (reset-max-key! *max-key key))
+  ([max-key-atom key]
+   (when (and key (or (nil? @max-key-atom)
+                     (> (compare key @max-key-atom) 0)))
+    (reset! max-key-atom key))))
 
 (defn gen-key
   ([]
    (gen-key @*max-key nil))
   ([end]
    (gen-key @*max-key end))
-  ([start end]
+  ([start end & {:keys [max-key-atom]
+                 :or {max-key-atom *max-key}}]
    (let [k (index/generate-key-between start end)]
-     (reset-max-key! k)
+     (reset-max-key! max-key-atom k)
      k)))
 
 (defn get-max-order
   [db]
   (:v (first (d/rseek-datoms db :avet :block/order))))
 
-(defn get-prev-order
-  [db current-key]
-  (:v (second (d/rseek-datoms db :avet :block/order current-key))))
-
-(defn get-next-order
-  [db current-key]
-  (:v (second (d/seek-datoms db :avet :block/order current-key))))
-
 (defn gen-n-keys
-  [n start end]
+  [n start end & {:keys [max-key-atom]
+                  :or {max-key-atom *max-key}}]
   (let [ks (index/generate-n-keys-between start end n)]
-    (reset-max-key! (last ks))
+    (reset-max-key! max-key-atom (last ks))
     ks))
+
+(defn get-prev-order
+  [db property value-id]
+  (let [value (d/entity db value-id)]
+    (if property
+      (let [values (->> (:property/closed-values property)
+                        reverse)]
+        (some (fn [e]
+                (when (and (< (compare (:block/order e) (:block/order value)) 0)
+                           (not= (:db/id e) (:db/id value)))
+                  (:block/order e))) values))
+      (let [properties (->> (d/datoms db :avet :block/type "property")
+                            (map (fn [d] (d/entity db (:e d))))
+                            (sort-by :block/order)
+                            reverse)]
+        (some (fn [property]
+                (when (and (< (compare (:block/order property) (:block/order value)) 0)
+                           (not= (:db/id property) (:db/id value)))
+                  (:block/order property))) properties)))))
+
+(defn get-next-order
+  [db property value-id]
+  (let [value (d/entity db value-id)]
+    (if property
+      (let [values (:property/closed-values property)]
+        (some (fn [e]
+                (when (and (> (compare (:block/order e) (:block/order value)) 0)
+                           (not= (:db/id e) (:db/id value)))
+                  (:block/order e))) values))
+      (let [properties (->> (d/datoms db :avet :block/type "property")
+                            (map (fn [d] (d/entity db (:e d))))
+                            (sort-by :block/order))]
+        (some (fn [property]
+                (when (and (> (compare (:block/order property) (:block/order value)) 0)
+                           (not= (:db/id property) (:db/id value)))
+                  (:block/order property))) properties)))))

+ 5 - 7
deps/db/src/logseq/db/frontend/property.cljs

@@ -250,13 +250,12 @@
 (defn get-closed-property-values
   [db property-id]
   (when-let [property (d/entity db property-id)]
-    (get-in property [:block/schema :values])))
+    (:property/closed-values property)))
 
 (defn closed-value-name
   "Gets name of closed value given closed value ent/map. Works for all closed value types including pages, blocks"
   [ent]
   (or (:block/original-name ent)
-      (:property/schema.value ent)
       (:block/content ent)))
 
 (defn get-closed-value-entity-by-name
@@ -264,10 +263,9 @@
   found. Works for all closed value types"
   [db db-ident value-name]
   (let [values (get-closed-property-values db db-ident)]
-    (some (fn [id]
-            (let [e (d/entity db [:block/uuid id])]
-              (when (= (closed-value-name e) value-name)
-                e))) values)))
+    (some (fn [e]
+            (when (= (closed-value-name e) (str value-name))
+              e)) values)))
 
 ;; TODO: db ident should obey clojure's rules for keywords
 (defn create-db-ident-from-name
@@ -303,4 +301,4 @@
        (:logseq.property/created-from-property block)
        (:block/page block)
        ;; not closed value
-       (not (some? (:property/schema.value block)))))
+       (not (some? (:block/content block)))))

+ 15 - 12
deps/db/src/logseq/db/frontend/property/build.cljs

@@ -1,7 +1,8 @@
 (ns logseq.db.frontend.property.build
   "Builds core property concepts"
   (:require [logseq.db.sqlite.util :as sqlite-util]
-            [logseq.db.frontend.property.type :as db-property-type]))
+            [logseq.db.frontend.property.type :as db-property-type]
+            [logseq.db.frontend.order :as db-order]))
 
 (defonce hidden-page-name-prefix "$$$")
 
@@ -11,8 +12,8 @@
    :block/format :markdown
    :block/uuid block-id
    :block/page page-id
-   :logseq.property/created-from-property (:db/ident property)
-   :property/schema.value value
+   :block/content (str value)
+   :block/closed-value-property (:db/ident property)
    :block/parent page-id})
 
 (defn build-closed-value-block
@@ -47,9 +48,8 @@
 (defn build-closed-values
   "Builds all the tx needed for property with closed values including
    the hidden page and closed value blocks as needed"
-  [db-ident prop-name property {:keys [property-attributes]}]
-  (let [property-schema (assoc (:block/schema property)
-                               :values (mapv :uuid (:closed-values property)))
+  [db-ident prop-name property {:keys [property-attributes from-ui-thread?]}]
+  (let [property-schema (:block/schema property)
         property-tx (merge (sqlite-util/build-new-property db-ident property-schema {:original-name prop-name
                                                                                      :ref-type? true})
                            property-attributes)
@@ -62,12 +62,15 @@
           (let [page-tx (build-property-hidden-page property-tx)
                 closed-value-blocks-tx
                 (map (fn [{:keys [db-ident value icon description uuid]}]
-                       (build-closed-value-block
-                        uuid
-                        value
-                        [:block/uuid (:block/uuid page-tx)]
-                        property
-                        {:db-ident db-ident :icon icon :description description}))
+                       (cond->
+                        (build-closed-value-block
+                         uuid
+                         value
+                         [:block/uuid (:block/uuid page-tx)]
+                         property
+                         {:db-ident db-ident :icon icon :description description})
+                         (not from-ui-thread?)
+                         (assoc :block/order (db-order/gen-key))))
                      (:closed-values property))]
             (into [page-tx] closed-value-blocks-tx)))]
     (into [property-tx] hidden-tx)))

+ 3 - 3
deps/db/src/logseq/db/frontend/property/type.cljs

@@ -20,7 +20,7 @@
 
 (def closed-value-property-types
   "Valid schema :type for closed values"
-  #{:string :number :url :page :date})
+  #{:string :number :url})
 
 (assert (set/subset? closed-value-property-types (set user-built-in-property-types))
         "All closed value types are valid property types")
@@ -79,7 +79,7 @@
   (or (url? val)
       (macro-url? val)
       (when-let [ent (d/entity db val)]
-        (url? (:property/schema.value ent)))))
+        (url? (:block/content ent)))))
 
 (defn- property-value-block?
   [db s]
@@ -102,7 +102,7 @@
   [db s]
   (or (string? s)
       (when-let [entity (d/entity db s)]
-        (string? (:property/schema.value entity)))))
+        (string? (:block/content entity)))))
 
 (def built-in-validation-schemas
   "Map of types to malli validation schemas that validate a property value for that type"

+ 1 - 1
deps/db/src/logseq/db/frontend/rules.cljc

@@ -234,7 +234,7 @@
     :task
     '[(task ?b ?statuses)
       (property ?b :logseq.task/status ?v)
-      [?v :property/schema.value ?status]
+      [?v :block/content ?status]
       [(contains? ?statuses ?status)]]}))
 
 (defn extract-rules

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

@@ -129,7 +129,8 @@
                               :db/cardinality :db.cardinality/many
                               :db/index true}
     ;; closed value
-    :property/schema.value {:db/index true}
+    :block/closed-value-property {:db/valueType :db.type/ref
+                                  :db/cardinality :db.cardinality/many}
 
     :file/last-modified-at {}
     :asset/uuid {:db/unique :db.unique/identity}

+ 2 - 2
src/main/frontend/commands.cljs

@@ -125,7 +125,7 @@
 
 (defn db-based-statuses
   []
-  (map (fn [id] (:property/schema.value (db/entity [:block/uuid id])))
+  (map (fn [e] (:block/content e))
        (pu/get-closed-property-values :logseq.task/status)))
 
 (defn db-based-embed-page
@@ -161,7 +161,7 @@
 
 (defn db-based-priorities
   []
-  (map (fn [id] (:property/schema.value (db/entity [:block/uuid id])))
+  (map (fn [e] (:block/content e))
     (pu/get-closed-property-values :logseq.task/priority)))
 
 (defn get-priorities

+ 7 - 10
src/main/frontend/components/property.cljs

@@ -152,9 +152,6 @@
           (let [type (keyword (string/lower-case v))
                 update-schema-fn (apply comp
                                         #(assoc % :type type)
-                                             ;; always delete previous closed values as they
-                                             ;; are not valid for the new type
-                                        #(dissoc % :values)
                                         (keep
                                          (fn [attr]
                                            (when-not (db-property-type/property-type-allows-schema-attribute? type attr)
@@ -302,7 +299,7 @@
           (when (db-property-type/property-type-allows-schema-attribute? (:type @*property-schema) :classes)
             (case (:type @*property-schema)
               :page
-              (when (empty? (:values @*property-schema))
+              (when (empty? (:property/closed-values property))
                 [:div.grid.grid-cols-4.gap-1.items-center.leading-8
                  [:label "Specify classes:"]
                  (class-select *property-schema
@@ -326,11 +323,11 @@
             [:div.grid.grid-cols-4.gap-1.items-start.leading-8
              [:label.col-span-1 "Available choices:"]
              [:div.col-span-3
-              (closed-value/choices property *property-name *property-schema opts)]])
+              (closed-value/choices property *property-schema opts)]])
 
           (when (and enable-closed-values?
                      (db-property-type/property-type-allows-schema-attribute? (:type @*property-schema) :position)
-                     (seq (:values @*property-schema)))
+                     (seq (:property/closed-values property)))
             (let [position (:position @*property-schema)
                   choices (map
                            (fn [item]
@@ -411,7 +408,7 @@
 
         (and (not add-class-property?)
              (= :default (get-in property [:block/schema :type]))
-             (not (seq (get-in property [:block/schema :values]))))
+             (not (seq (:property/closed-values property))))
         (do
           (pv/<create-new-block! entity property "")
           nil)
@@ -681,7 +678,7 @@
   (when (keyword? k)
     (when-let [property (db/sub-block (:db/id (db/entity k)))]
       (let [type (get-in property [:block/schema :type] :default)
-            closed-values? (seq (get-in property [:block/schema :values]))
+            closed-values? (seq (:property/closed-values property))
             v-block (when (integer? v) (db/entity v))
             block? (and v-block
                         (not closed-values?)
@@ -732,9 +729,9 @@
                                        active (db/entity (keyword active-id))
                                        over-order (:block/order over)
                                        new-order (if move-down?
-                                                   (let [next-order (db-order/get-next-order (db/get-db) over-order)]
+                                                   (let [next-order (db-order/get-next-order (db/get-db) nil (:db/id over))]
                                                      (db-order/gen-key over-order next-order))
-                                                   (let [prev-order (db-order/get-prev-order (db/get-db) over-order)]
+                                                   (let [prev-order (db-order/get-prev-order (db/get-db) nil (:db/id over))]
                                                      (db-order/gen-key prev-order over-order)))]
                                    (db/transact! (state/get-current-repo)
                                                  [{:db/id (:db/id active)

+ 36 - 24
src/main/frontend/components/property/closed_value.cljs

@@ -8,7 +8,6 @@
             [logseq.shui.ui :as shui]
             [frontend.components.dnd :as dnd]
             [frontend.components.icon :as icon-component]
-            [frontend.components.property.util :as pu-component]
             [frontend.handler.property :as property-handler]
             [frontend.handler.db-based.property :as db-property-handler]
             [frontend.config :as config]
@@ -18,14 +17,16 @@
             [frontend.state :as state]
             [promesa.core :as p]
             [logseq.db.frontend.property :as db-property]
-            [logseq.db.frontend.property.type :as db-property-type]))
+            [logseq.db.frontend.property.type :as db-property-type]
+            [logseq.db.frontend.order :as db-order]
+            [logseq.outliner.core :as outliner-core]))
 
 (defn- <upsert-closed-value!
   "Create new closed value and returns its block UUID."
   [property item]
   (p/let [{:keys [block-id tx-data]} (db-property-handler/<upsert-closed-value property item)]
     (p/do!
-     (when (seq tx-data) (db/transact! tx-data))
+     (when (seq tx-data) (db/transact! (state/get-current-repo) tx-data {:outliner-op :upsert-closed-value}))
      (when (seq tx-data) (db-property-handler/re-init-commands! property))
      block-id)))
 
@@ -147,7 +148,7 @@
         (ui/icon "X")])]))
 
 (rum/defc choice-item-content
-  [property *property-schema block parent-opts]
+  [property block parent-opts]
   (let [{:block/keys [uuid]} block]
     (let [content-fn
           (if config/publishing?
@@ -173,16 +174,14 @@
        (assoc opts
               :delete-choice
               (fn []
-                (p/let [success? (db-property-handler/delete-closed-value! property block)]
-                  (when success?
-                    (swap! *property-schema update :values (fn [vs] (vec (remove #(= uuid %) vs)))))))
+                (db-property-handler/delete-closed-value! property block))
               :update-icon
               (fn [icon]
                 (property-handler/set-block-property! (state/get-current-repo) (:block/uuid block) :logseq.property/icon icon)))
        parent-opts))))
 
 (rum/defc add-existing-values
-  [property *property-schema values {:keys [toggle-fn]}]
+  [property values {:keys [toggle-fn]}]
   [:div.flex.flex-col.gap-1.w-64.p-4.overflow-y-auto
    {:class "max-h-[50dvh]"}
    [:div "Existing values:"]
@@ -196,30 +195,43 @@
    (ui/button
     "Add choices"
     {:on-click (fn []
-                 (p/let [closed-values (db-property-handler/<add-existing-values-to-closed-values! property values)]
-                   (swap! *property-schema assoc :values closed-values)
+                 (p/let [_ (db-property-handler/<add-existing-values-to-closed-values! property values)]
                    (toggle-fn)))})])
 
 (rum/defc choices < rum/reactive
-  [property *property-name *property-schema opts]
+  [property *property-schema opts]
   (let [schema (:block/schema property)
+        values (:property/closed-values property)
         property-type (:type schema)
-        values (:values schema)
         dropdown-opts {:modal-class (util/hiccup->class
                                      "origin-top-right.absolute.left-0.rounded-md.shadow-lg")}]
     [:div.closed-values.flex.flex-col
      (let [choices (doall
-                    (keep (fn [id]
-                            (when-let [block (db/sub-block (:db/id (db/entity [:block/uuid id])))]
-                              {:id (str id)
-                               :value id
-                               :content (choice-item-content property *property-schema block (merge opts dropdown-opts))}))
+                    (keep (fn [value]
+                            (when-let [block (db/sub-block (:db/id value))]
+                              (let [id (:block/uuid block)]
+                                {:id (str id)
+                                 :value id
+                                 :content (choice-item-content property block (merge opts dropdown-opts))})))
                           values))]
        (dnd/items choices
-                  {:on-drag-end (fn [new-values]
-                                  (when (seq new-values)
-                                    (swap! *property-schema assoc :values new-values)
-                                    (pu-component/update-property! property @*property-name @*property-schema)))}))
+                  {:on-drag-end (fn [_ {:keys [active-id over-id direction]}]
+                                  (let [move-down? (= direction :down)
+                                        over (db/entity [:block/uuid (uuid over-id)])
+                                        active (db/entity [:block/uuid (uuid active-id)])
+                                        over-order (:block/order over)
+                                        new-order (if move-down?
+                                                    (let [next-order (db-order/get-next-order (db/get-db) property (:db/id over))]
+                                                      (db-order/gen-key over-order next-order))
+                                                    (let [prev-order (db-order/get-prev-order (db/get-db) property (:db/id over))]
+                                                      (db-order/gen-key prev-order over-order)))]
+
+                                    (db/transact! (state/get-current-repo)
+                                                  [{:db/id (:db/id active)
+                                                    :block/order new-order}
+                                                   (outliner-core/block-with-updated-at
+                                                    {:db/id (:db/id property)})]
+                                                  {:outliner-op :save-block})))}))
      (if config/publishing?
        (constantly [])
        (shui/button
@@ -228,9 +240,9 @@
          :on-click
          (fn [e]
            (p/let [values (db-async/<get-block-property-values (state/get-current-repo) (:db/ident property))
-                   existing-values (seq (get-in property [:block/schema :values]))
+                   existing-values (seq (:property/closed-values property))
                    values (if (seq existing-values)
-                            (let [existing-ids (set (map #(:db/id (db/entity [:block/uuid %])) existing-values))]
+                            (let [existing-ids (set (map :db/id existing-values))]
                               (remove (fn [[_ id]] (existing-ids id)) values))
                             values)]
              (shui/popup-show! (.-target e)
@@ -242,7 +254,7 @@
                                                     (remove string/blank?)
                                                     distinct)]
                                    (if (seq values')
-                                     (add-existing-values property *property-schema values' opts)
+                                     (add-existing-values property values' opts)
                                      (if (= :page property-type)
                                        (property-value/select-page property
                                                                    {:multiple-choices? false

+ 17 - 18
src/main/frontend/components/property/value.cljs

@@ -57,7 +57,7 @@
   [property type]
   (or (contains? #{:page :number :url :date} type)
       ;; closed values
-      (seq (get-in property [:block/schema :values]))))
+      (seq (:property/closed-values property))))
 
 (defn exit-edit-property
   []
@@ -256,7 +256,7 @@
                                   (map :block/original-name v)
                                   [(:block/original-name v)])))
                             (remove nil?)))
-        closed-values (seq (get-in property [:block/schema :values]))
+        closed-values (seq (:property/closed-values property))
         pages (->>
                (cond
                  (seq classes)
@@ -270,7 +270,7 @@
                   classes)
 
                  (and block closed-values)
-                 (map (fn [id] (:block/original-name (db/entity [:block/uuid id]))) closed-values)
+                 (map (fn [e] (:block/original-name e)) closed-values)
 
                  :else
                  (model/get-all-page-original-names repo))
@@ -384,18 +384,17 @@
       (let [schema (:block/schema property)
             property (db/sub-block (:db/id property))
             type (:type schema)
-            closed-values? (seq (:values schema))
+            closed-values? (seq (:property/closed-values property))
             items (if closed-values?
-                    (keep (fn [id]
-                            (when-let [block (when id (db/entity [:block/uuid id]))]
-                              (let [icon (pu/get-block-property-value block :logseq.property/icon)
-                                    value (db-property/closed-value-name block)]
-                                {:label (if icon
-                                          [:div.flex.flex-row.gap-2
-                                           (icon-component/icon icon)
-                                           value]
-                                          value)
-                                 :value (:db/id block)}))) (:values schema))
+                    (keep (fn [block]
+                            (let [icon (pu/get-block-property-value block :logseq.property/icon)
+                                  value (db-property/closed-value-name block)]
+                              {:label (if icon
+                                        [:div.flex.flex-row.gap-2
+                                         (icon-component/icon icon)
+                                         value]
+                                        value)
+                               :value (:db/id block)})) (:property/closed-values property))
                     (->> values
                          (mapcat (fn [[_id value]]
                                    (if (coll? value)
@@ -564,7 +563,7 @@
 
 (rum/defc select-item
   [property type value {:keys [page-cp inline-text _icon?] :as opts}]
-  (let [closed-values? (seq (get-in property [:block/schema :values]))]
+  (let [closed-values? (seq (:property/closed-values property))]
     [:div.select-item
      (cond
        (= value :logseq.property/empty-placeholder)
@@ -741,7 +740,7 @@
                      (state/sub-property-value-editing? editor-id)
                      (state/sub-editing? [container-id (:block/uuid block) (:block/uuid property)]))
         select-type? (select-type? property type)
-        closed-values? (seq (:values schema))
+        closed-values? (seq (:property/closed-values property))
         select-opts {:on-chosen on-chosen}
         value (if (and (de/entity? value) (= (:db/ident value) :logseq.property/empty-placeholder))
                 nil
@@ -772,8 +771,8 @@
         ;; :others
           [:div.flex.flex-1
            (if editing?
-               (property-editing block property value schema editor-box editor-args editor-id)
-               (property-value-inner block property value opts))])))))
+             (property-editing block property value schema editor-box editor-args editor-id)
+             (property-value-inner block property value opts))])))))
 
 (rum/defc multiple-values
   [block property v {:keys [on-chosen dropdown? editing? block-cp editor-box]

+ 1 - 1
src/main/frontend/handler/common/developer.cljs

@@ -21,7 +21,7 @@
         ;; handles page uuids and closed values w/o knowing type
         get-uuid-prop-value (fn [v]
                               (or (db-pu/get-property-name v)
-                                  (:property/schema.value (db/entity [:block/uuid v]))))
+                                  (:block/content (db/entity [:block/uuid v]))))
         result (cond-> result*
                  (and (seq (:block/properties entity)) (config/db-based-graph? (state/get-current-repo)))
                  (assoc :block.debug/properties

+ 49 - 56
src/main/frontend/handler/db_based/property.cljs

@@ -22,7 +22,8 @@
             [promesa.core :as p]
             [frontend.db.async :as db-async]
             [logseq.db :as ldb]
-            [logseq.db.frontend.malli-schema :as db-malli-schema]))
+            [logseq.db.frontend.malli-schema :as db-malli-schema]
+            [logseq.db.frontend.order :as db-order]))
 
 ;; schema -> type, cardinality, object's class
 ;;           min, max -> string length, number range, cardinality size limit
@@ -88,8 +89,7 @@
   [property {:keys [type cardinality values]}]
   (let [ident (:db/ident property)
         cardinality (if (= cardinality :many) :db.cardinality/many :db.cardinality/one)
-        type-data (when (and type (or (db-property-type/ref-property-types type)
-                                      (seq values))) ; type changes or closed values
+        type-data (when (and type (or (db-property-type/ref-property-types type) (seq values))) ; type changes or closed values
                     {:db/ident ident
                      :db/valueType :db.type/ref
                      :db/cardinality cardinality})]
@@ -142,7 +142,7 @@
               (or (not= (:type schema) (get-in property [:block/schema :type]))
                   (not= (:cardinality schema) (get-in property [:block/schema :cardinality]))
                   (and (= :default (:type schema)) (not= :db.type/ref (:db/valueType property)))
-                  (seq (:values schema)))
+                  (seq (:property/closed-values property)))
               (conj (update-datascript-schema property schema)))
             tx-data (concat property-tx-data
                             (when (seq properties)
@@ -539,13 +539,10 @@
 (defn replace-closed-value
   [property new-id old-id]
   (assert (and (uuid? new-id) (uuid? old-id)))
-  (let [schema (-> (:block/schema property)
-                   (update :values (fn [values]
-                                     (vec (conj (remove #{old-id} values) new-id)))))]
-    (db/transact! (state/get-current-repo)
-                  [{:db/id (:db/id property)
-                    :block/schema schema}]
-                  {:outliner-op :save-block})))
+  (db/transact! (state/get-current-repo)
+                [[:db/retract [:block/uuid old-id] :block/closed-value-property (:db/id property)]
+                 [:db/add [:block/uuid new-id] :block/closed-value-property (:db/id property)]]
+                {:outliner-op :save-block}))
 
 (defn <upsert-closed-value
   "id should be a block UUID or nil"
@@ -557,13 +554,12 @@
       (p/let [property (db/entity (:db/id property))
               value (if (string? value) (string/trim value) value)
               property-schema (:block/schema property)
-              closed-values (:values property-schema)
+              closed-values (:property/closed-values property)
               default-closed-values? (and (= :default property-type) (seq closed-values))
               value (if (and default-closed-values? (string? value) (not (string/blank? value)))
                       (p/let [result (create-property-text-block! nil property value nil {})]
                         (:db/id (db/entity [:block/uuid (:block-id result)])))
                       value)
-              block-values (map (fn [id] (db/entity [:block/uuid id])) closed-values)
               resolved-value (try
                                (convert-property-input-string (:type property-schema) value)
                                (catch :default e
@@ -578,7 +574,7 @@
         (cond
           (some (fn [b] (and (= resolved-value (or (db-pu/property-value-when-closed b)
                                                    (:block/uuid b)))
-                             (not= id (:block/uuid b)))) block-values)
+                             (not= id (:block/uuid b)))) closed-values)
           (do
             (notification/show! "Choice already exists" :warning)
             :value-exists)
@@ -592,10 +588,8 @@
           nil
 
           (db/page? value-block)             ; page
-          (let [new-values (vec (conj closed-values value))]
-            {:block-id value
-             :tx-data [{:db/id (:db/id property)
-                        :block/schema (assoc property-schema :values new-values)}]})
+          {:block-id value
+           :tx-data [[:db/add [:block/uuid value] :property/value-property (:db/id property)]]}
 
           :else
           (let [block-id (or id (db/new-block-id))
@@ -605,32 +599,32 @@
                 tx-data (if block
                           [(let [schema (:block/schema block)]
                              (cond->
-                              {:block/uuid id
-                               :property/schema.value resolved-value
-                               :block/schema (if description
-                                               (assoc schema :description description)
-                                               (dissoc schema :description))}
+                              (outliner-core/block-with-updated-at
+                               {:block/uuid id
+                                :block/content resolved-value
+                                :block/schema (if description
+                                                (assoc schema :description description)
+                                                (dissoc schema :description))})
                                icon
                                (assoc :logseq.property/icon icon)))]
                           (let [hidden-tx
                                 (if (contains? db-property-type/ref-property-types (:type property-schema))
                                   []
                                   (let [page (get-property-hidden-page property)
-                                        new-block (db-property-build/build-closed-value-block block-id resolved-value [:block/uuid (:block/uuid page)]
-                                                                                              property {:icon icon
-                                                                                                        :description description})]
+                                        max-order (:block/order (last (:property/closed-values property)))
+                                        new-block (-> (db-property-build/build-closed-value-block block-id resolved-value [:block/uuid (:block/uuid page)]
+                                                                                                  property {:icon icon
+                                                                                                            :description description})
+                                                      (assoc :block/order (db-order/gen-key max-order nil)))]
                                     (cond-> []
                                       (not (e/entity? page))
                                       (conj page)
                                       true
-                                      (conj new-block))))
-                                new-values (if (contains? db-property-type/ref-property-types (:type property-schema))
-                                             (vec (conj closed-values (:block/uuid (db/entity resolved-value))))
-                                             (vec (conj closed-values block-id)))]
+                                      (conj new-block))))]
                             (conj hidden-tx
-                                  {:db/id (:db/id property)
-                                   :block/schema (merge {:type property-type}
-                                                        (assoc property-schema :values new-values))})))]
+                                  (outliner-core/block-with-updated-at
+                                   {:db/id (:db/id property)
+                                    :block/schema (merge {:type property-type} property-schema)}))))]
             {:block-id block-id
              :tx-data tx-data}))))))
 
@@ -642,35 +636,38 @@
     (let [values' (remove string/blank? values)
           property-schema (:block/schema property)]
       (if (every? uuid? values')
-        (p/let [new-value-ids (vec (remove #(nil? (db/entity [:block/uuid %])) values'))]
-          (when (seq new-value-ids)
+        (p/let [value-ids (vec (remove #(nil? (db/entity [:block/uuid %])) values'))]
+          (when (seq value-ids)
             (let [property-tx {:db/ident (:db/ident property)
                                :db/valueType :db.type/ref
                                :db/cardinality (:db/cardinality property)
-                               :block/schema (assoc property-schema :values new-value-ids)}]
-              (db/transact! (state/get-current-repo) [property-tx]
+                               :block/schema property-schema}
+                  value-property-tx (map (fn [id] [:db/add [:block/uuid id] :property/value-property (:db/id property)]) value-ids)]
+              (db/transact! (state/get-current-repo) (cons property-tx value-property-tx)
                             {:outliner-op :insert-blocks})
-              new-value-ids)))
+              value-ids)))
         (p/let [property-id (:db/ident property)
                 page (get-property-hidden-page property)
                 page-tx (when-not (e/entity? page) page)
                 page-id (:block/uuid page)
-                closed-value-blocks (map (fn [value]
-                                           (db-property-build/build-closed-value-block
-                                            (db/new-block-id)
-                                            value
-                                            [:block/uuid page-id]
-                                            property
-                                            {}))
-                                         values')
+                *max-key (atom nil)
+                closed-value-blocks (doall
+                                     (map (fn [value]
+                                            (let [b (db-property-build/build-closed-value-block
+                                                     (db/new-block-id)
+                                                     value
+                                                     [:block/uuid page-id]
+                                                     property
+                                                     {})]
+                                              (assoc b :block/order (db-order/gen-key @*max-key nil))))
+                                          values'))
                 value->block-id (zipmap
-                                 (map :property/schema.value closed-value-blocks)
+                                 (map :block/content closed-value-blocks)
                                  (map :block/uuid closed-value-blocks))
-                new-value-ids (mapv :block/uuid closed-value-blocks)
                 property-tx {:db/ident (:db/ident property)
                              :db/valueType :db.type/ref
                              :db/cardinality (:db/cardinality property)
-                             :block/schema (assoc property-schema :values new-value-ids)}
+                             :block/schema property-schema}
                 property-values (db-async/<get-block-property-values (state/get-current-repo) (:db/ident property))
                 block-values (->> property-values
                                   (remove #(uuid? (first %))))
@@ -690,8 +687,7 @@
                                   {:db/id id property-id value'}))
                               id-values))]
           (db/transact! (state/get-current-repo) tx-data
-                        {:outliner-op :insert-blocks})
-          new-value-ids)))))
+                        {:outliner-op :insert-blocks}))))))
 
 (defn delete-closed-value!
   "Returns true when deleted or if not deleted displays warning and returns false"
@@ -707,12 +703,9 @@
 
     :else
     (let [property (db/entity (:db/id property))
-          schema (:block/schema property)
           tx-data [[:db/retractEntity (:db/id value-block)]
-                   {:db/id (:db/id property)
-                    :block/schema (update schema :values
-                                          (fn [values]
-                                            (vec (remove #{(:block/uuid value-block)} values))))}]]
+                   (outliner-core/block-with-updated-at
+                    {:db/id (:db/id property)})]]
       (p/do!
        (db/transact! tx-data)
        (re-init-commands! property)

+ 2 - 2
src/main/frontend/handler/db_based/property/util.cljs

@@ -25,7 +25,7 @@
        (map (fn [[k v]]
               (let [prop-ent (db-utils/entity k)
                     readable-property-val
-                    #(if (seq (get-in prop-ent [:block/schema :values])) ; closed values
+                    #(if (seq (:property/closed-values prop-ent)) ; closed values
                        (when-let [block (db-utils/entity [:block/uuid %])]
                          (db-property/closed-value-name block))
                        %)]
@@ -39,4 +39,4 @@
   "Returns property value if the given entity is type 'closed value' or nil"
   [ent]
   (when (contains? (:block/type ent) "closed value")
-    (:property/schema.value ent)))
+    (:block/content ent)))

+ 3 - 3
src/main/frontend/worker/search.cljs

@@ -186,7 +186,7 @@
   "Returns property value if the given entity is type 'closed value' or nil"
   [ent]
   (when (contains? (:block/type ent) "closed value")
-    (:property/schema.value ent)))
+    (:block/content ent)))
 
 (defn get-by-parent-&-left
   [db parent-id left-id]
@@ -245,12 +245,12 @@
         properties (dissoc properties :logseq.property/created-from-property)]
     (when-not (or
                (and page? name (whiteboard-page? db uuid))
-               (and block? (> (count content) 10000))
+               (and block? (string? content) (> (count content) 10000))
                (and (empty? properties)
                     (or (and block? (string/blank? content))
                         (and db-based? page?))))        ; empty page or block
       (let [content (if block?
-                      content
+                      (when (string? content) content)
                       ;; File based page content
                       (if db-based?
                         ""            ; empty page content

+ 5 - 5
src/test/frontend/handler/db_based/property_closed_value_test.cljs

@@ -27,12 +27,12 @@
 
 (defn- get-value-ids
   [k]
-  (:values (:block/schema (db/entity k))))
+  (map :block/uuid (:property/closed-values (db/entity k))))
 
 (defn- get-closed-values
   "Get value from block ids"
   [values]
-  (set (map #(:property/schema.value (db/entity [:block/uuid %])) values)))
+  (set (map #(:block/content (db/entity [:block/uuid %])) values)))
 
 ;; closed values related
 ;; upsert-closed-value
@@ -66,7 +66,7 @@
          (p/let [{:keys [block-id tx-data]} (db-property-handler/<upsert-closed-value property {:value 3})]
            (db/transact! tx-data)
            (let [b (db/entity [:block/uuid block-id])]
-             (is (= 3 (:property/schema.value b)))
+             (is (= 3 (:block/content b)))
              (is (contains? (:block/type b) "closed value"))
              (let [values (get-value-ids k)]
                (is (= #{1 2 3} (get-closed-values values))))
@@ -77,11 +77,11 @@
                                                                                              :description "choice 4"})]
                  (db/transact! tx-data)
                  (let [b (db/entity [:block/uuid block-id])]
-                   (is (= 4 (:property/schema.value b)))
+                   (is (= 4 (:block/content b)))
                    (is (= "choice 4" (:description (:block/schema b))))
                    (is (contains? (:block/type b) "closed value"))
                    (p/let [_ (db-property-handler/delete-closed-value! property (db/entity [:block/uuid block-id]))]
 
                      (testing "Delete closed value"
                        (is (nil? (db/entity [:block/uuid block-id])))
-                       (is (= 2 (count (:values (:block/schema (db/entity k))))))))))))))))))
+                       (is (= 2 (count (:property/closed-values (db/entity k)))))))))))))))))