Переглянути джерело

Merge branch 'master' into refactor/apis-types

charlie 4 тижнів тому
батько
коміт
eb80a4ba75

+ 105 - 67
deps/db/src/logseq/db/frontend/rules.cljc

@@ -96,19 +96,11 @@
       [(>= ?d ?start)]
       [(>= ?d ?start)]
       [(<= ?d ?end)]]
       [(<= ?d ?end)]]
 
 
-    :existing-property-value
-    '[;; non-ref value
-      [(existing-property-value ?b ?prop ?val)
-       [?prop-e :db/ident ?prop]
-       [(missing? $ ?prop-e :db/valueType)]
-       [?b ?prop ?val]]
-      ;; ref value
-      [(existing-property-value ?b ?prop ?val)
-       [?prop-e :db/ident ?prop]
-       [?prop-e :db/valueType :db.type/ref]
-       [?b ?prop ?pv]
-       (or [?pv :block/title ?val]
-           [?pv :logseq.property/value ?val])]]
+    :ref->val
+    '[[(ref->val ?pv ?val)
+       [?pv :block/title ?val]]
+      [(ref->val ?pv ?val)
+       [?pv :logseq.property/value ?val]]]
 
 
     :property-missing-value
     :property-missing-value
     '[(property-missing-value ?b ?prop-e ?default-p ?default-v)
     '[(property-missing-value ?b ?prop-e ?default-p ?default-v)
@@ -121,31 +113,30 @@
       [(= ?prop-v "N/A")]
       [(= ?prop-v "N/A")]
       [?prop-e ?default-p ?default-v]]
       [?prop-e ?default-p ?default-v]]
 
 
-    :property-scalar-default-value
-    '[(property-scalar-default-value ?b ?prop-e ?default-p ?val)
-      (property-missing-value ?b ?prop-e ?default-p ?default-v)
-      [(missing? $ ?prop-e :db/valueType)]
-      [?prop-e ?default-p ?val]]
+    :scalar-property-value
+    '[[(scalar-property-value ?b ?prop-e ?val)
+       [?prop-e :db/ident ?prop]
+       [?b ?prop ?val]]]
 
 
-    :property-default-value
-    '[(property-default-value ?b ?prop-e ?default-p ?val)
-      (property-missing-value ?b ?prop-e ?default-p ?default-v)
-      (or
-       [?default-v :block/title ?val]
-       [?default-v :logseq.property/value ?val])]
+    :scalar-property-value-with-default
+    '[[(scalar-property-value-with-default ?b ?prop-e ?val)
+       (scalar-property-value ?b ?prop-e ?val)]
+
+      [(scalar-property-value-with-default ?b ?prop-e ?val)
+       (property-missing-value ?b ?prop-e :logseq.property/scalar-default-value ?val)]]
 
 
-    :property-value
-    '[[(property-value ?b ?prop-e ?val)
+    :ref-property-value
+    '[[(ref-property-value ?b ?prop-e ?val)
        [?prop-e :db/ident ?prop]
        [?prop-e :db/ident ?prop]
-       (existing-property-value ?b ?prop ?val)]
-      [(property-value ?b ?prop-e ?val)
-       (or
-        (and
-         [(missing? $ ?prop-e :db/valueType)]
-         (property-scalar-default-value ?b ?prop-e :logseq.property/scalar-default-value ?val))
-        (and
-         [?prop-e :db/valueType :db.type/ref]
-         (property-default-value ?b ?prop-e :logseq.property/default-value ?val)))]]
+       [?b ?prop ?pv]
+       (ref->val ?pv ?val)]]
+
+    :ref-property-value-with-default
+    '[[(ref-property-value-with-default ?b ?prop-e ?val)
+       (ref-property-value ?b ?prop-e ?val)]
+      [(ref-property-value-with-default ?b ?prop-e ?val)
+       (property-missing-value ?b ?prop-e :logseq.property/default-value ?pv)
+       (ref->val ?pv ?val)]]
 
 
     :object-has-class-property
     :object-has-class-property
     '[(object-has-class-property? ?b ?prop)
     '[(object-has-class-property? ?b ?prop)
@@ -190,7 +181,65 @@
        [(missing? $ ?prop-e :logseq.property/public?)]
        [(missing? $ ?prop-e :logseq.property/public?)]
        [?prop-e :logseq.property/public? true])]
        [?prop-e :logseq.property/public? true])]
 
 
-    ;; Checks if a property has a value for any features that are not simple queries
+    ;; Checks if a property has a value for simple queries. Supports default values
+    :scalar-property
+    '[(scalar-property ?b ?prop ?val)
+      [?prop-e :db/ident ?prop]
+      (scalar-property-value ?b ?prop-e ?val)
+      (or
+       [(missing? $ ?prop-e :logseq.property/public?)]
+       [?prop-e :logseq.property/public? true])]
+
+    :scalar-property-with-default
+    '[(scalar-property-with-default ?b ?prop ?val)
+      [?prop-e :db/ident ?prop]
+      (scalar-property-value-with-default ?b ?prop-e ?val)
+      (or
+       [(missing? $ ?prop-e :logseq.property/public?)]
+       [?prop-e :logseq.property/public? true])]
+
+    :ref-property
+    '[(ref-property ?b ?prop ?val)
+      [?prop-e :db/ident ?prop]
+      (ref-property-value ?b ?prop-e ?val)
+      (or
+       [(missing? $ ?prop-e :logseq.property/public?)]
+       [?prop-e :logseq.property/public? true])]
+
+    :ref-property-with-default
+    '[(ref-property-with-default ?b ?prop ?val)
+      [?prop-e :db/ident ?prop]
+      (ref-property-value-with-default ?b ?prop-e ?val)
+      (or
+       [(missing? $ ?prop-e :logseq.property/public?)]
+       [?prop-e :logseq.property/public? true])]
+
+    ;; Same as ref-property/scalar-property except it returns public and private properties like :block/title
+    :private-scalar-property
+    '[(private-scalar-property ?b ?prop ?val)
+      [?prop-e :db/ident ?prop]
+      [?prop-e :block/tags :logseq.class/Property]
+      (scalar-property-value ?b ?prop-e ?val)]
+
+    :private-scalar-property-with-default
+    '[(private-scalar-property-with-default ?b ?prop ?val)
+      [?prop-e :db/ident ?prop]
+      [?prop-e :block/tags :logseq.class/Property]
+      (scalar-property-value-with-default ?b ?prop-e ?val)]
+
+    :private-ref-property
+    '[(private-ref-property ?b ?prop ?val)
+      [?prop-e :db/ident ?prop]
+      [?prop-e :block/tags :logseq.class/Property]
+      (ref-property-value ?b ?prop-e ?val)]
+
+    :private-ref-property-with-default
+    '[(private-ref-property-with-default ?b ?prop ?val)
+      [?prop-e :db/ident ?prop]
+      [?prop-e :block/tags :logseq.class/Property]
+      (ref-property-value-with-default ?b ?prop-e ?val)]
+
+    ;; `property` is slow, don't use it for user-facing queries
     :property
     :property
     '[(property ?b ?prop ?val)
     '[(property ?b ?prop ?val)
       [?prop-e :db/ident ?prop]
       [?prop-e :db/ident ?prop]
@@ -210,23 +259,6 @@
         (or [?pv :block/title ?val]
         (or [?pv :block/title ?val]
             [?pv :logseq.property/value ?val])))]
             [?pv :logseq.property/value ?val])))]
 
 
-    ;; Checks if a property has a value for simple queries. Supports default values
-    :simple-query-property
-    '[(simple-query-property ?b ?prop ?val)
-      [?prop-e :db/ident ?prop]
-      [?prop-e :block/tags :logseq.class/Property]
-      (or
-       [(missing? $ ?prop-e :logseq.property/public?)]
-       [?prop-e :logseq.property/public? true])
-      (property-value ?b ?prop-e ?val)]
-
-    ;; Same as property except it returns public and private properties like :block/title
-    :private-simple-query-property
-    '[(private-simple-query-property ?b ?prop ?val)
-      [?prop-e :db/ident ?prop]
-      [?prop-e :block/tags :logseq.class/Property]
-      (property-value ?b ?prop-e ?val)]
-
     :tags
     :tags
     '[(tags ?b ?tags)
     '[(tags ?b ?tags)
       [?b :block/tags ?tag]
       [?b :block/tags ?tag]
@@ -235,15 +267,13 @@
 
 
     :task
     :task
     '[(task ?b ?statuses)
     '[(task ?b ?statuses)
-      ;; and needed to avoid binding error
-      (and (simple-query-property ?b :logseq.property/status ?val)
-           [(contains? ?statuses ?val)])]
+      (ref-property-with-default ?b :logseq.property/status ?val)
+      [(contains? ?statuses ?val)]]
 
 
     :priority
     :priority
     '[(priority ?b ?priorities)
     '[(priority ?b ?priorities)
-      ;; and needed to avoid binding error
-      (and (simple-query-property ?b :logseq.property/priority ?priority)
-           [(contains? ?priorities ?priority)])]}))
+      (ref-property-with-default ?b :logseq.property/priority ?priority)
+      [(contains? ?priorities ?priority)]]}))
 
 
 (def rules-dependencies
 (def rules-dependencies
   "For db graphs, a map of rule names and the rules they depend on. If this map
   "For db graphs, a map of rule names and the rules they depend on. If this map
@@ -251,18 +281,26 @@
   like find-rules-in-where"
   like find-rules-in-where"
   {:has-ref #{:parent}
   {:has-ref #{:parent}
    :page-ref #{:has-ref}
    :page-ref #{:has-ref}
-   :task #{:simple-query-property}
-   :priority #{:simple-query-property}
-   :property-missing-value #{:object-has-class-property}
+
+   ;; simple query helpers
+   :task #{:ref-property-with-default}
+   :priority #{:ref-property-with-default}
    :has-property-or-object-property #{:object-has-class-property}
    :has-property-or-object-property #{:object-has-class-property}
    :object-has-class-property #{:class-extends}
    :object-has-class-property #{:class-extends}
    :has-simple-query-property #{:has-property-or-object-property}
    :has-simple-query-property #{:has-property-or-object-property}
    :has-private-simple-query-property #{:has-property-or-object-property}
    :has-private-simple-query-property #{:has-property-or-object-property}
-   :property-default-value #{:existing-property-value :property-missing-value}
-   :property-scalar-default-value #{:existing-property-value :property-missing-value}
-   :property-value #{:property-default-value :property-scalar-default-value}
-   :simple-query-property #{:property-value}
-   :private-simple-query-property #{:property-value}})
+   :property-missing-value #{:object-has-class-property}
+   :ref-property-value #{:ref->val}
+   :scalar-property #{:scalar-property-value}
+   :scalar-property-with-default #{:scalar-property-value-with-default}
+   :scalar-property-value-with-default #{:scalar-property-value :property-missing-value}
+   :ref-property #{:ref-property-value}
+   :ref-property-value-with-default #{:ref-property-value :property-missing-value}
+   :ref-property-with-default #{:ref-property-value-with-default}
+   :private-scalar-property #{:scalar-property-value}
+   :private-scalar-property-with-default #{:scalar-property-value-with-default}
+   :private-ref-property #{:ref-property-value}
+   :private-ref-property-with-default #{:ref-property-value-with-default}})
 
 
 (defn- get-full-deps
 (defn- get-full-deps
   [deps rules-deps]
   [deps rules-deps]

+ 12 - 15
deps/db/test/logseq/db/frontend/rules_test.cljs

@@ -11,17 +11,14 @@
        (rules/extract-rules rules/db-query-dsl-rules)))
        (rules/extract-rules rules/db-query-dsl-rules)))
 
 
 (deftest get-full-deps
 (deftest get-full-deps
-  (let [default-value-deps #{:property-default-value :property-missing-value :existing-property-value
-                             :object-has-class-property :class-extends}
-        property-value-deps (conj default-value-deps :property-value :property-scalar-default-value)
-        property-deps (conj property-value-deps :simple-query-property)
+  (let [property-value-deps #{:ref->val :class-extends :object-has-class-property :property-missing-value :ref-property-value :ref-property-value-with-default}
+        property-deps (conj property-value-deps :ref-property-with-default)
         task-deps (conj property-deps :task)
         task-deps (conj property-deps :task)
         priority-deps (conj property-deps :priority)
         priority-deps (conj property-deps :priority)
         task-priority-deps (into priority-deps task-deps)]
         task-priority-deps (into priority-deps task-deps)]
     (are [x y] (= y (#'rules/get-full-deps x rules/rules-dependencies))
     (are [x y] (= y (#'rules/get-full-deps x rules/rules-dependencies))
-      [:property-default-value] default-value-deps
-      [:property-value] property-value-deps
-      [:simple-query-property] property-deps
+      [:ref-property-value-with-default] property-value-deps
+      [:ref-property-with-default] property-deps
       [:task] task-deps
       [:task] task-deps
       [:priority] priority-deps
       [:priority] priority-deps
       [:task :priority] task-priority-deps)))
       [:task :priority] task-priority-deps)))
@@ -50,7 +47,7 @@
                          @conn))
                          @conn))
         "has-property can bind to property arg")))
         "has-property can bind to property arg")))
 
 
-(deftest property-rule
+(deftest ref-property-rule
   (let [conn (db-test/create-conn-with-blocks
   (let [conn (db-test/create-conn-with-blocks
               {:properties {:foo {:logseq.property/type :default}
               {:properties {:foo {:logseq.property/type :default}
                             :foo2 {:logseq.property/type :default}
                             :foo2 {:logseq.property/type :default}
@@ -65,36 +62,36 @@
                         :build/properties {:foo "bar A"}}}]})]
                         :build/properties {:foo "bar A"}}}]})]
     (testing "cardinality :one property"
     (testing "cardinality :one property"
       (is (= ["Page1"]
       (is (= ["Page1"]
-             (->> (q-with-rules '[:find (pull ?b [:block/title]) :where (property ?b :user.property/foo "bar")]
+             (->> (q-with-rules '[:find (pull ?b [:block/title]) :where (ref-property ?b :user.property/foo "bar")]
                                 @conn)
                                 @conn)
                   (map (comp :block/title first))))
                   (map (comp :block/title first))))
           "property returns result when page has property")
           "property returns result when page has property")
       (is (= []
       (is (= []
-             (->> (q-with-rules '[:find (pull ?b [:block/title]) :where (property ?b :user.property/foo "baz")]
+             (->> (q-with-rules '[:find (pull ?b [:block/title]) :where (ref-property ?b :user.property/foo "baz")]
                                 @conn)
                                 @conn)
                   (map (comp :block/title first))))
                   (map (comp :block/title first))))
           "property returns no result when page doesn't have property value")
           "property returns no result when page doesn't have property value")
       (is (= #{:user.property/foo}
       (is (= #{:user.property/foo}
              (->> (q-with-rules '[:find [?p ...]
              (->> (q-with-rules '[:find [?p ...]
-                                  :where (property ?b ?p "bar") [?b :block/title "Page1"]]
+                                  :where (ref-property ?b ?p "bar") [?b :block/title "Page1"]]
                                 @conn)
                                 @conn)
                   set))
                   set))
           "property can bind to property arg with bound property value"))
           "property can bind to property arg with bound property value"))
 
 
     (testing "cardinality :many property"
     (testing "cardinality :many property"
       (is (= ["Page1"]
       (is (= ["Page1"]
-             (->> (q-with-rules '[:find (pull ?b [:block/title]) :where (property ?b :user.property/number-many 5)]
+             (->> (q-with-rules '[:find (pull ?b [:block/title]) :where (ref-property ?b :user.property/number-many 5)]
                                 @conn)
                                 @conn)
                   (map (comp :block/title first))))
                   (map (comp :block/title first))))
           "property returns result when page has property")
           "property returns result when page has property")
       (is (= []
       (is (= []
-             (->> (q-with-rules '[:find (pull ?b [:block/title]) :where (property ?b :user.property/number-many 20)]
+             (->> (q-with-rules '[:find (pull ?b [:block/title]) :where (ref-property ?b :user.property/number-many 20)]
                                 @conn)
                                 @conn)
                   (map (comp :block/title first))))
                   (map (comp :block/title first))))
           "property returns no result when page doesn't have property value")
           "property returns no result when page doesn't have property value")
       (is (= #{:user.property/number-many}
       (is (= #{:user.property/number-many}
              (->> (q-with-rules '[:find [?p ...]
              (->> (q-with-rules '[:find [?p ...]
-                                  :where (property ?b ?p 5) [?b :block/title "Page1"]]
+                                  :where (ref-property ?b ?p 5) [?b :block/title "Page1"]]
                                 @conn)
                                 @conn)
                   set))
                   set))
           "property can bind to property arg with bound property value"))
           "property can bind to property arg with bound property value"))
@@ -103,7 +100,7 @@
     (testing ":ref property"
     (testing ":ref property"
       (is (= ["Page1"]
       (is (= ["Page1"]
              (->> (q-with-rules '[:find (pull ?b [:block/title])
              (->> (q-with-rules '[:find (pull ?b [:block/title])
-                                  :where (property ?b :user.property/page-many "Page A")]
+                                  :where (ref-property ?b :user.property/page-many "Page A")]
                                 @conn)
                                 @conn)
                   (map (comp :block/title first))))
                   (map (comp :block/title first))))
           "property returns result when page has property")
           "property returns result when page has property")

+ 2 - 4
libs/README.md

@@ -22,10 +22,8 @@ import "@logseq/libs"
 
 
 #### Community templates
 #### Community templates
 
 
-1. https://github.com/pengx17/logseq-plugin-template-react
-2. https://github.com/pengx17/logseq-plugin-template-svelte
-3. https://github.com/tiensonqin/logseq-cljs-playground
-4. https://github.com/YU000jp/logseq-plugin-sample-kit-typescript
+1. https://github.com/logseq/cljs-plugin-example
+2. https://github.com/YU000jp/logseq-plugin-sample-kit-typescript
 
 
 #### Feedback
 #### Feedback
 If you have any feedback or encounter any issues, feel free to join Logseq's discord group.
 If you have any feedback or encounter any issues, feel free to join Logseq's discord group.

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

@@ -300,7 +300,7 @@
           (shui/alert
           (shui/alert
            {:variant "warning"}
            {:variant "warning"}
            (shui/alert-description
            (shui/alert-description
-            "⚠️ PDF annotations should be with internal asset(pdf) ref block to work properly."))
+            "Creating a local asset from an external one. PDF annotations require a local asset to work properly."))
 
 
           (let [title (util/node-path.basename url)]
           (let [title (util/node-path.basename url)]
             (edit-external-url-form asset-block {:url url :title title :on-saved on-saved!}))])))])
             (edit-external-url-form asset-block {:url url :title title :on-saved on-saved!}))])))])

+ 78 - 66
src/main/frontend/components/repo.cljs

@@ -484,74 +484,86 @@
   (let [[creating-db? set-creating-db?] (hooks/use-state false)
   (let [[creating-db? set-creating-db?] (hooks/use-state false)
         [cloud? set-cloud?] (hooks/use-state false)
         [cloud? set-cloud?] (hooks/use-state false)
         [e2ee-rsa-key-ensured? set-e2ee-rsa-key-ensured?] (hooks/use-state nil)
         [e2ee-rsa-key-ensured? set-e2ee-rsa-key-ensured?] (hooks/use-state nil)
-        input-ref (hooks/create-ref)]
+        input-ref (hooks/create-ref)
+        new-db-f (fn new-db-f
+                   [graph-name]
+                   (when-not (or (string/blank? graph-name)
+                                 creating-db?)
+                     (if (invalid-graph-name? graph-name)
+                       (invalid-graph-name-warning)
+                       (do
+                         (set-creating-db? true)
+                         (p/let [repo (repo-handler/new-db! graph-name)]
+                           (when cloud?
+                             (->
+                              (p/do
+                                (state/set-state! :rtc/uploading? true)
+                                (rtc-handler/<rtc-create-graph! repo)
+                                (rtc-flows/trigger-rtc-start repo)
+                                (rtc-handler/<get-remote-graphs))
+                              (p/catch (fn [error]
+                                         (log/error :create-db-failed error)))
+                              (p/finally (fn []
+                                           (state/set-state! :rtc/uploading? false)
+                                           (set-creating-db? false)))))
+                           (shui/dialog-close!))))))
+        submit! (fn submit!
+                  [^js e click?]
+                  (when-let [value (and (or click? (= (gobj/get e "key") "Enter"))
+                                        (util/trim-safe (.-value (rum/deref input-ref))))]
+                    (new-db-f value)))]
     (hooks/use-effect!
     (hooks/use-effect!
      (fn []
      (fn []
        (when-let [^js input (hooks/deref input-ref)]
        (when-let [^js input (hooks/deref input-ref)]
          (js/setTimeout #(.focus input) 32)))
          (js/setTimeout #(.focus input) 32)))
      [])
      [])
-    (letfn [(new-db-f [graph-name]
-              (when-not (or (string/blank? graph-name)
-                            creating-db?)
-                (if (invalid-graph-name? graph-name)
-                  (invalid-graph-name-warning)
-                  (do
-                    (set-creating-db? true)
-                    (p/let [repo (repo-handler/new-db! graph-name)]
-                      (when cloud?
-                        (->
-                         (p/do
-                           (state/set-state! :rtc/uploading? true)
-                           (rtc-handler/<rtc-create-graph! repo)
-                           (rtc-flows/trigger-rtc-start repo)
-                           (rtc-handler/<get-remote-graphs))
-                         (p/catch (fn [error]
-                                    (log/error :create-db-failed error)))
-                         (p/finally (fn []
-                                      (state/set-state! :rtc/uploading? false)
-                                      (set-creating-db? false)))))
-                      (shui/dialog-close!))))))
-            (submit! [^js e click?]
-              (when-let [value (and (or click? (= (gobj/get e "key") "Enter"))
-                                    (util/trim-safe (.-value (rum/deref input-ref))))]
-                (new-db-f value)))]
-      [:div.new-graph.flex.flex-col.gap-4.p-1.pt-2
-       (shui/input
-        {:disabled creating-db?
-         :ref input-ref
-         :placeholder "your graph name"
-         :on-key-down submit!
-         :autoComplete "off"})
-       (when (user-handler/rtc-group?)
-         [:div.flex.flex-col
-          [:div.flex.flex-row.items-center.gap-1
-           (shui/checkbox
-            {:id "rtc-sync"
-             :value cloud?
-             :on-checked-change
-             (fn []
-               (let [v (boolean (not cloud?))
-                     token (state/get-auth-id-token)
-                     user-uuid (user-handler/user-uuid)]
-                 (set-cloud? v)
-                 (when (and (true? v) (not e2ee-rsa-key-ensured?))
-                   (when (and token user-uuid)
-                     (-> (p/let [rsa-key-pair (state/<invoke-db-worker :thread-api/get-user-rsa-key-pair token user-uuid)]
-                           (set-e2ee-rsa-key-ensured? (some? rsa-key-pair)))
-                         (p/catch (fn [e]
-                                    (log/error :get-user-rsa-key-pair e)
-                                    e)))))))})
-           [:label.opacity-70.text-sm
-            {:for "rtc-sync"}
-            "Use Logseq Sync?"]]
-          (when (false? e2ee-rsa-key-ensured?)
-            [:label.opacity-70.text-sm
-             {:for "rtc-sync"}
-             "Need to init E2EE settings first, Settings > Encryption"])])
-       (shui/button
-        {:disabled (and cloud? (not e2ee-rsa-key-ensured?))
-         :on-click #(submit! % true)
-         :on-key-down submit!}
-        (if creating-db?
-          (ui/loading "Creating graph")
-          "Submit"))])))
+
+    (hooks/use-effect!
+     (fn []
+       (let [token (state/get-auth-id-token)
+             user-uuid (user-handler/user-uuid)
+             refresh-token (str (state/get-auth-refresh-token))
+             db-name (util/trim-safe (.-value (rum/deref input-ref)))]
+         (when (and cloud? refresh-token token user-uuid
+                    (not e2ee-rsa-key-ensured?))
+           (p/do!
+            (state/<invoke-db-worker :thread-api/init-user-rsa-key-pair
+                                     token
+                                     refresh-token
+                                     user-uuid))
+           (-> (p/let [rsa-key-pair (state/<invoke-db-worker :thread-api/get-user-rsa-key-pair token user-uuid)]
+                 (set-e2ee-rsa-key-ensured? (some? rsa-key-pair))
+                 (when rsa-key-pair
+                   (when db-name (new-db-f db-name))))
+               (p/catch (fn [e]
+                          (log/error :get-user-rsa-key-pair e)
+                          e))))))
+     [cloud?])
+
+    [:div.new-graph.flex.flex-col.gap-4.p-1.pt-2
+     (shui/input
+      {:disabled creating-db?
+       :ref input-ref
+       :placeholder "your graph name"
+       :on-key-down submit!
+       :autoComplete "off"})
+     (when (user-handler/rtc-group?)
+       [:div.flex.flex-col
+        [:div.flex.flex-row.items-center.gap-1
+         (shui/checkbox
+          {:id "rtc-sync"
+           :value cloud?
+           :on-checked-change
+           (fn []
+             (let [v (boolean (not cloud?))]
+               (set-cloud? v)))})
+         [:label.opacity-70.text-sm
+          {:for "rtc-sync"}
+          "Use Logseq Sync?"]]])
+     (shui/button
+      {:disabled (and cloud? (not e2ee-rsa-key-ensured?))
+       :on-click #(submit! % true)
+       :on-key-down submit!}
+      (if creating-db?
+        (ui/loading "Creating graph")
+        "Submit"))]))

+ 122 - 44
src/main/frontend/db/query_dsl.cljs

@@ -178,32 +178,51 @@
 
 
 (defonce remove-nil? (partial remove nil?))
 (defonce remove-nil? (partial remove nil?))
 
 
+(defn- not-clause? [c]
+  (and (seq? c) (= 'not (first c))))
+
+(defn- distinct-preserve-order [xs]
+  (let [seen (volatile! #{})]
+    (reduce (fn [acc x]
+              (if (contains? @seen x)
+                acc
+                (do (vswap! seen conj x)
+                    (conj acc x))))
+            [] xs)))
+
 (defn- build-and-or-not
 (defn- build-and-or-not
   [e {:keys [current-filter vars] :as env} level fe]
   [e {:keys [current-filter vars] :as env} level fe]
   (let [raw-clauses (map (fn [form]
   (let [raw-clauses (map (fn [form]
                            (build-query form (assoc env :current-filter fe) (inc level)))
                            (build-query form (assoc env :current-filter fe) (inc level)))
                          (rest e))
                          (rest e))
+
+        ;; preserve order (no hash-order surprises)
         clauses (->> raw-clauses
         clauses (->> raw-clauses
                      (map :query)
                      (map :query)
                      remove-nil?
                      remove-nil?
-                     (distinct))
-        nested-and? (and (= fe 'and) (= current-filter 'and))]
-    (when (seq clauses)
-      (let [result (build-and-or-not-result
-                    fe clauses current-filter nested-and?)
-            vars' (set/union (set @vars) (collect-vars result))
-            query (cond
-                    nested-and?
-                    result
-
-                    (and (zero? level) (contains? #{'and 'or} fe))
-                    result
+                     (distinct-preserve-order))
+
+        ;; for (and ...), ensure any (not ...) comes AFTER positive binders
+        clauses (if (= fe 'and)
+                  (let [[nots others] (reduce (fn [[ns os] c]
+                                                (if (not-clause? c)
+                                                  [(conj ns c) os]
+                                                  [ns (conj os c)]))
+                                              [[] []]
+                                              clauses)]
+                    (concat others nots))
+                  clauses)
 
 
-                    (and (= 'not fe) (some? current-filter))
-                    result
+        nested-and? (and (= fe 'and) (= current-filter 'and))]
 
 
-                    :else
-                    [result])]
+    (when (seq clauses)
+      (let [result (build-and-or-not-result fe clauses current-filter nested-and?)
+            vars'  (set/union (set @vars) (collect-vars result))
+            query  (cond
+                     nested-and? result
+                     (and (zero? level) (contains? #{'and 'or} fe)) result
+                     (and (= 'not fe) (some? current-filter)) result
+                     :else [result])]
         (reset! vars vars')
         (reset! vars vars')
         {:query query
         {:query query
          :rules (distinct (mapcat :rules raw-clauses))}))))
          :rules (distinct (mapcat :rules raw-clauses))}))))
@@ -343,13 +362,38 @@
   [e {:keys [db-graph? private-property?]}]
   [e {:keys [db-graph? private-property?]}]
   (let [k (if db-graph? (->db-keyword-property (nth e 1)) (->file-keyword-property (nth e 1)))
   (let [k (if db-graph? (->db-keyword-property (nth e 1)) (->file-keyword-property (nth e 1)))
         v (nth e 2)
         v (nth e 2)
-        v' (if db-graph? (->db-property-value k v) (->file-property-value v))]
+        v' (if db-graph? (->db-property-value k v) (->file-property-value v))
+        property (when (qualified-keyword? k)
+                   (db-utils/entity k))
+        ref-type? (= :db.type/ref (:db/valueType property))]
     (if db-graph?
     (if db-graph?
-      (if private-property?
-        {:query (list 'private-simple-query-property '?b k v')
-         :rules [:private-simple-query-property]}
-        {:query (list 'simple-query-property '?b k v')
-         :rules [:simple-query-property]})
+      (let [default-value (if ref-type?
+                            (when-let [value (:logseq.property/default-value property)]
+                              (or (:block/title value)
+                                  (:logseq.property/value value)))
+                            (:logseq.property/scalar-default-value property))
+            default-value? (and (some? v') (= default-value v'))
+            rule (if private-property?
+                   (cond
+                     (and ref-type? default-value?)
+                     :private-ref-property-with-default
+                     ref-type?
+                     :private-ref-property
+                     default-value?
+                     :private-scalar-property-with-default
+                     :else
+                     :private-scalar-property)
+                   (cond
+                     (and ref-type? default-value?)
+                     :ref-property-with-default
+                     ref-type?
+                     :ref-property
+                     default-value?
+                     :scalar-property-with-default
+                     :else
+                     :scalar-property))]
+        {:query (list (symbol (name rule)) '?b k v')
+         :rules [rule]})
       {:query (list 'property '?b k v')
       {:query (list 'property '?b k v')
        :rules [:property]})))
        :rules [:property]})))
 
 
@@ -662,35 +706,69 @@ Some bindings in this fn:
               (string/replace #"^#" "#tag ")
               (string/replace #"^#" "#tag ")
               (string/replace tag-placeholder "#")))))
               (string/replace tag-placeholder "#")))))
 
 
+(defn- lvar? [x]
+  (and (symbol? x) (= \? (first (name x)))))
+
+(defn- collect-vars-by-polarity
+  "Returns {:pos #{?vars} :neg #{?vars}}.
+   Vars inside (not ...) are counted as negative."
+  [form]
+  (let [pos (volatile! #{})
+        neg (volatile! #{})]
+    (letfn [(walk* [x positive?]
+              (cond
+                (lvar? x)
+                (vswap! (if positive? pos neg) conj x)
+
+                (and (seq? x) (= 'not (first x)))
+                (doseq [c (rest x)] (walk* c false))
+
+                (sequential? x)
+                (doseq [c x] (walk* c positive?))
+
+                (map? x)
+                (do (doseq [k (keys x)] (walk* k positive?))
+                    (doseq [v (vals x)] (walk* v positive?)))
+
+                :else nil))]
+      (walk* form true)
+      {:pos @pos :neg @neg})))
+
 (defn- add-bindings!
 (defn- add-bindings!
   [q {:keys [db-graph?]}]
   [q {:keys [db-graph?]}]
-  (let [forms (set (flatten q))
-        syms ['?b '?p 'not]
-        [b? p? not?] (-> (set/intersection (set syms) forms)
-                         (map syms))]
-    (cond
-      not?
-      (cond
-        (and b? p?)
-        (concat [['?b :block/uuid] ['?p :block/name] ['?b :block/page '?p]] q)
+  (let [{:keys [pos neg]} (collect-vars-by-polarity q)
 
 
-        b?
-        (if db-graph?
-          ;; This keeps built-in properties from showing up in not results.
-          ;; May need to be revisited as more class and property filters are explored
-          (concat [['?b :block/uuid] '[(missing? $ ?b :logseq.property/built-in?)]] q)
-          (concat [['?b :block/uuid]] q))
+        appears?      (fn [v] (or (contains? pos v) (contains? neg v)))
+        needs-domain? (fn [v] (and (appears? v) (not (contains? pos v))))
 
 
-        p?
-        (concat [['?p :block/name]] q)
+        b-need? (needs-domain? '?b)
+        p-need? (needs-domain? '?p)
 
 
-        :else
-        q)
+        ;; CASE 1: both needed → link them, do NOT enumerate all blocks
+        bindings
+        (cond
+          (and b-need? p-need?)
+          [['?b :block/page '?p]]
 
 
-      (and b? p?)
-      (concat [['?b :block/page '?p]] q)
+          ;; CASE 2: only ?b needed → last-resort domain (true global negation)
+          b-need?
+          (if db-graph?
+            [['?b :block/uuid]
+             '[(missing? $ ?b :logseq.property/built-in?)]]
+            [['?b :block/uuid]])
 
 
-      :else
+          ;; CASE 3: only ?p needed
+          p-need?
+          [['?p :block/name]]
+
+          ;; CASE 4: both already positive → optional link (cheap + useful)
+          (and (contains? pos '?b) (contains? pos '?p))
+          [['?b :block/page '?p]]
+
+          :else
+          nil)]
+    (if (seq bindings)
+      (concat bindings q)   ;; IMPORTANT: bindings FIRST
       q)))
       q)))
 
 
 (defn simplify-query
 (defn simplify-query

+ 13 - 25
src/main/frontend/db/query_react.cljs

@@ -2,7 +2,6 @@
   "Custom queries."
   "Custom queries."
   (:require [clojure.string :as string]
   (:require [clojure.string :as string]
             [clojure.walk :as walk]
             [clojure.walk :as walk]
-            [frontend.config :as config]
             [frontend.date :as date]
             [frontend.date :as date]
             [frontend.db.conn :as conn]
             [frontend.db.conn :as conn]
             [frontend.db.model :as model]
             [frontend.db.model :as model]
@@ -94,27 +93,16 @@
 
 
 (defn react-query
 (defn react-query
   [repo {:keys [query inputs rules] :as query'} query-opts]
   [repo {:keys [query inputs rules] :as query'} query-opts]
-  (let [pprint (if config/dev? #(when (state/developer-mode?) (apply prn %&)) (fn [_] nil))
-        start-time (.now js/performance)]
-    (when config/dev? (js/console.groupCollapsed "react-query logs:"))
-    (pprint "================")
-    (pprint "Use the following to debug your datalog queries:")
-    (pprint query')
-
-    (let [query (resolve-query query)
-          repo (or repo (state/get-current-repo))
-          db (conn/get-db repo)
-          resolve-with (select-keys query-opts [:current-page-fn :current-block-uuid])
-          resolved-inputs (mapv #(resolve-input db % resolve-with) inputs)
-          inputs (cond-> resolved-inputs
-                   rules
-                   (conj rules))
-          k [:custom
-             (or (:query-string query') (dissoc query' :title))
-             (:today-query? query-opts)
-             inputs]]
-      (pprint "inputs (post-resolution):" resolved-inputs)
-      (pprint "query-opts:" query-opts)
-      (pprint (str "time elapsed: " (.toFixed (- (.now js/performance) start-time) 2) "ms"))
-      (when config/dev? (js/console.groupEnd))
-      [k (apply react/q repo k query-opts query inputs)])))
+  (let [query (resolve-query query)
+        repo (or repo (state/get-current-repo))
+        db (conn/get-db repo)
+        resolve-with (select-keys query-opts [:current-page-fn :current-block-uuid])
+        resolved-inputs (mapv #(resolve-input db % resolve-with) inputs)
+        inputs (cond-> resolved-inputs
+                 rules
+                 (conj rules))
+        k [:custom
+           (or (:query-string query') (dissoc query' :title))
+           (:today-query? query-opts)
+           inputs]]
+    [k (apply react/q repo k query-opts query inputs)]))

+ 17 - 3
src/main/frontend/worker/db_worker.cljs

@@ -49,6 +49,7 @@
             [logseq.db.common.sqlite :as common-sqlite]
             [logseq.db.common.sqlite :as common-sqlite]
             [logseq.db.common.view :as db-view]
             [logseq.db.common.view :as db-view]
             [logseq.db.frontend.class :as db-class]
             [logseq.db.frontend.class :as db-class]
+            [logseq.db.frontend.property :as db-property]
             [logseq.db.sqlite.create-graph :as sqlite-create-graph]
             [logseq.db.sqlite.create-graph :as sqlite-create-graph]
             [logseq.db.sqlite.export :as sqlite-export]
             [logseq.db.sqlite.export :as sqlite-export]
             [logseq.db.sqlite.gc :as sqlite-gc]
             [logseq.db.sqlite.gc :as sqlite-gc]
@@ -244,8 +245,19 @@
             conn (common-sqlite/get-storage-conn storage schema)
             conn (common-sqlite/get-storage-conn storage schema)
             _ (db-fix/check-and-fix-schema! repo conn)
             _ (db-fix/check-and-fix-schema! repo conn)
             _ (when datoms
             _ (when datoms
-                (let [data (map (fn [datom]
-                                  [:db/add (:e datom) (:a datom) (:v datom)]) datoms)]
+                (let [eid->datoms (group-by :e datoms)
+                      {properties true non-properties false} (group-by
+                                                              (fn [[_eid datoms]]
+                                                                (boolean
+                                                                 (some (fn [datom] (and (= (:a datom) :db/ident)
+                                                                                        (db-property/property? (:v datom))))
+                                                                       datoms)))
+                                                              eid->datoms)
+                      datoms (concat (mapcat second properties)
+                                     (mapcat second non-properties))
+                      data (map (fn [datom]
+                                  [:db/add (:e datom) (:a datom) (:v datom)])
+                                datoms)]
                   (d/transact! conn data {:initial-db? true})))
                   (d/transact! conn data {:initial-db? true})))
             client-ops-conn (when-not @*publishing? (common-sqlite/get-storage-conn
             client-ops-conn (when-not @*publishing? (common-sqlite/get-storage-conn
                                                      client-ops-storage
                                                      client-ops-storage
@@ -387,7 +399,9 @@
 (def-thread-api :thread-api/q
 (def-thread-api :thread-api/q
   [repo inputs]
   [repo inputs]
   (when-let [conn (worker-state/get-datascript-conn repo)]
   (when-let [conn (worker-state/get-datascript-conn repo)]
-    (apply d/q (first inputs) @conn (rest inputs))))
+    (worker-util/profile
+     (str "Datalog query: " inputs)
+     (apply d/q (first inputs) @conn (rest inputs)))))
 
 
 (def-thread-api :thread-api/datoms
 (def-thread-api :thread-api/datoms
   [repo & args]
   [repo & args]

+ 1 - 1
src/resources/dicts/en.edn

@@ -277,7 +277,7 @@
  :settings-page/tab-assets "Assets"
  :settings-page/tab-assets "Assets"
  :settings-page/tab-features "Features"
  :settings-page/tab-features "Features"
  :settings-page/tab-collaboration "Collaboration"
  :settings-page/tab-collaboration "Collaboration"
- :settings-page/tab-encryption "End-to-end encryption"
+ :settings-page/tab-encryption "Encryption"
  :settings-page/plugin-system "Plugins"
  :settings-page/plugin-system "Plugins"
  :settings-page/enable-flashcards "Flashcards"
  :settings-page/enable-flashcards "Flashcards"
  :settings-page/network-proxy "Network proxy"
  :settings-page/network-proxy "Network proxy"