Browse Source

fix: queries with default values

and objects that are descendants of a tag with
a default-value property. Fixes
https://test.logseq.com/#/page/67551ea7-bd58-48bb-a0ea-8b976fa94423.
Also extended sqlite.build to allow closed value properties to
be configured with :build/properties
Gabriel Horner 1 year ago
parent
commit
bcdd162145

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

@@ -155,6 +155,7 @@
    (dissoc query-dsl-rules :namespace
            :page-property :has-page-property
            :page-tags :all-page-tags)
+   (dissoc rules :namespace)
    {:existing-property-value
     '[;; non-ref value
       [(existing-property-value ?b ?prop ?val)
@@ -210,7 +211,10 @@
     '[(object-has-class-property? ?b ?prop)
       [?prop-e :db/ident ?prop]
       [?t :logseq.property.class/properties ?prop-e]
-      [?b :block/tags ?t]]
+      [?b :block/tags ?tc]
+      (or
+       [(= ?t ?tc)]
+       (parent ?t ?tc))]
 
     :has-property-or-default-value
     '[(has-property-or-default-value? ?b ?prop)
@@ -313,6 +317,7 @@
    :priority #{:property}
    :property-missing-value #{:object-has-class-property}
    :has-property-or-default-value #{:object-has-class-property}
+   :object-has-class-property #{:parent}
    :has-simple-query-property #{:has-property-or-default-value}
    :has-private-simple-query-property #{:has-property-or-default-value}
    :property-default-value #{:existing-property-value :property-missing-value}

+ 41 - 34
deps/db/src/logseq/db/sqlite/build.cljs

@@ -141,45 +141,52 @@
                        {:block/title (db-content/title-ref->id-ref (:block/title m) block-refs {:replace-tag? false})
                         :block/refs block-refs})))))))
 
+(defn- build-property-tx
+  [properties page-uuids all-idents property-db-ids
+   [prop-name {:build/keys [schema-classes] :as prop-m}]]
+  (let [[new-block & additional-tx]
+        (if-let [closed-values (seq (map #(merge {:uuid (random-uuid)} %) (:build/closed-values prop-m)))]
+          (let [db-ident (get-ident all-idents prop-name)]
+            (db-property-build/build-closed-values
+             db-ident
+             prop-name
+             (assoc prop-m :db/ident db-ident :closed-values closed-values)
+             {:property-attributes
+              (merge {:db/id (or (property-db-ids prop-name)
+                                 (throw (ex-info "No :db/id for property" {:property prop-name})))}
+                     (select-keys prop-m [:build/properties-ref-types]))}))
+          [(merge (sqlite-util/build-new-property (get-ident all-idents prop-name)
+                                                  (:block/schema prop-m)
+                                                  {:block-uuid (:block/uuid prop-m)
+                                                   :title (:block/title prop-m)})
+                  {:db/id (or (property-db-ids prop-name)
+                              (throw (ex-info "No :db/id for property" {:property prop-name})))}
+                  (select-keys prop-m [:build/properties-ref-types]))])
+        pvalue-tx-m
+        (->property-value-tx-m new-block (:build/properties prop-m) properties all-idents)]
+    (cond-> []
+      (seq pvalue-tx-m)
+      (into (mapcat #(if (set? %) % [%]) (vals pvalue-tx-m)))
+      true
+      (conj
+       (merge
+        new-block
+        (when-let [props (not-empty (:build/properties prop-m))]
+          (->block-properties (merge props (db-property-build/build-properties-with-ref-values pvalue-tx-m)) page-uuids all-idents))
+        (when (seq schema-classes)
+          {:property/schema.classes
+           (mapv #(hash-map :db/ident (get-ident all-idents %))
+                 schema-classes)})))
+      true
+      (into additional-tx))))
+
 (defn- build-properties-tx [properties page-uuids all-idents]
   (let [property-db-ids (->> (keys properties)
                              (map #(vector % (new-db-id)))
                              (into {}))
         new-properties-tx (vec
-                           (mapcat
-                            (fn [[prop-name {:build/keys [schema-classes] :as prop-m}]]
-                              (if-let [closed-values (seq (map #(merge {:uuid (random-uuid)} %) (:build/closed-values prop-m)))]
-                                (let [db-ident (get-ident all-idents prop-name)]
-                                  (db-property-build/build-closed-values
-                                   db-ident
-                                   prop-name
-                                   (assoc prop-m :db/ident db-ident :closed-values closed-values)
-                                   {:property-attributes
-                                    {:db/id (or (property-db-ids prop-name)
-                                                (throw (ex-info "No :db/id for property" {:property prop-name})))}}))
-                                (let [new-block
-                                      (merge (sqlite-util/build-new-property (get-ident all-idents prop-name)
-                                                                             (:block/schema prop-m)
-                                                                             {:block-uuid (:block/uuid prop-m)
-                                                                              :title (:block/title prop-m)})
-                                             {:db/id (or (property-db-ids prop-name)
-                                                         (throw (ex-info "No :db/id for property" {:property prop-name})))}
-                                             (select-keys prop-m [:build/properties-ref-types]))
-                                      pvalue-tx-m (->property-value-tx-m new-block (:build/properties prop-m) properties all-idents)]
-                                  (cond-> []
-                                    (seq pvalue-tx-m)
-                                    (into (mapcat #(if (set? %) % [%]) (vals pvalue-tx-m)))
-                                    true
-                                    (conj
-                                     (merge
-                                      new-block
-                                      (when-let [props (not-empty (:build/properties prop-m))]
-                                        (->block-properties (merge props (db-property-build/build-properties-with-ref-values pvalue-tx-m)) page-uuids all-idents))
-                                      (when (seq schema-classes)
-                                        {:property/schema.classes
-                                         (mapv #(hash-map :db/ident (get-ident all-idents %))
-                                               schema-classes)})))))))
-                            properties))]
+                           (mapcat (partial build-property-tx properties page-uuids all-idents property-db-ids)
+                                   properties))]
     new-properties-tx))
 
 (defn- build-classes-tx [classes properties-config uuid-maps all-idents]

+ 2 - 4
deps/db/test/logseq/db/frontend/rules_test.cljs

@@ -11,10 +11,8 @@
        (rules/extract-rules rules/db-query-dsl-rules)))
 
 (deftest get-full-deps
-  (let [default-value-deps #{:property-default-value
-                             :property-missing-value
-                             :existing-property-value
-                             :object-has-class-property}
+  (let [default-value-deps #{:property-default-value :property-missing-value :existing-property-value
+                             :object-has-class-property :parent}
         property-value-deps (conj default-value-deps :property-value :property-scalar-default-value)
         property-deps (conj property-value-deps :simple-query-property)
         task-deps #{:property :task}

+ 1 - 1
scripts/src/logseq/tasks/db_graph/create_graph_with_properties.cljs

@@ -179,7 +179,7 @@
           (into (mapv #(vector (keyword (str (name %) "-closed"))
                                {:block/schema {:type %}
                                 :build/closed-values (closed-values-config (keyword (str (name %) "-closed")))})
-                      [:default :url :number #_:date]))
+                      [:default :url :number]))
           (into {}))}))
 
 (def spec

+ 36 - 4
src/test/frontend/db/query_dsl_test.cljs

@@ -256,7 +256,39 @@ prop-d:: [[nada]]"}])
         "Blocks with :checkbox property value or tagged with a tag that has that default-value property value")
     (is (= ["b2"]
            (map :block/title (dsl-query "(property :user.property/checkbox false)")))
-        "Blocks with :checkbox property value and not tagged with a tag that has that default-value property value")))
+        "Blocks with :checkbox property value and not tagged with a tag that has that default-value property value"))
+
+  (deftest closed-property-default-value-queries
+    (load-test-files-for-db-graph
+     {:properties
+      {:status {:block/schema {:type :default}
+                :build/closed-values
+                [{:value "Todo" :uuid (random-uuid)}
+                 {:value "Doing" :uuid (random-uuid)}]
+                :build/properties
+                {:logseq.property/default-value "Todo"}
+                :build/properties-ref-types {:entity :number}}}
+      :classes {:Mytask {:build/schema-properties [:status]}
+                :Bug {:build/class-parent :Mytask}}
+      :pages-and-blocks
+      [{:page {:block/title "page1"}
+        :blocks [{:block/title "task1"
+                  :build/properties {:status "Doing"}
+                  :build/tags [:Mytask]}
+                 {:block/title "task2"
+                  :build/tags [:Mytask]}
+                 {:block/title "bug1"
+                  :build/properties {:status "Doing"}
+                  :build/tags [:Bug]}
+                 {:block/title "bug2"
+                  :build/tags [:Bug]}]}]})
+
+    (is (= ["task2" "bug2"]
+           (map :block/title (dsl-query "(property status \"Todo\")")))
+        "Blocks or tagged with or descended from a tag that has closed default-value property")
+    (is (= ["task1" "bug1"]
+           (map :block/title (dsl-query "(property status \"Doing\")")))
+        "Blocks or tagged with or descended from a tag that don't have closed default-value property value")))
 
 (deftest block-property-query-performance
   (let [pages (->> (repeat 10 {:tags ["tag1" "tag2"]})
@@ -739,7 +771,7 @@ created-at:: 1608968448116
   (require '[clojure.pprint :as pprint])
   (test-helper/start-test-db!)
 
-  (query-dsl/query test-db "(task done)")
+  (query-dsl/query test-helper/test-db "(task done)")
 
  ;; Useful for debugging
   (prn
@@ -747,7 +779,7 @@ created-at:: 1608968448116
     '[:find (pull ?b [*])
       :where
       [?b :block/name]]
-    (frontend.db/get-db test-db)))
+    (frontend.db/get-db test-helper/test-db)))
 
  ;; (or (priority a) (not (priority a)))
  ;; FIXME: Error: Insufficient bindings: #{?priority} not bound in [(contains? #{"A"} ?priority)]
@@ -759,7 +791,7 @@ created-at:: 1608968448116
       (or (and [?b :block/priority ?priority] [(contains? #{"A"} ?priority)])
           (not [?b :block/priority #{"A"}]
                [(contains? #{"A"} ?priority)]))]
-    (frontend.db/get-db test-db))))
+    (frontend.db/get-db test-helper/test-db))))
 
 (when-not js/process.env.DB_GRAPH
   (deftest namespace-queries