浏览代码

feat: initial commands impl

Tienson Qin 10 月之前
父节点
当前提交
9da3129a2b

+ 75 - 0
src/main/frontend/worker/commands.cljs

@@ -0,0 +1,75 @@
+(ns frontend.worker.commands
+  "Invoke commands based on user settings"
+  (:require [datascript.core :as d]
+            [logseq.db.frontend.property.type :as db-property-type]
+            [cljs-time.core :as t]
+            [cljs-time.coerce :as tc]
+            [logseq.db.frontend.property :as db-property]))
+
+;; TODO: allow users to add command or configure it through #Command (which parent should be #Code)
+(def *commands
+  (atom
+   [[:repeated-task
+     {:title "Repeated task"
+      :entity-conditions [{:property :logseq.task/repeated?
+                           :value true}]
+      :tx-conditions [{:property :logseq.task/status
+                       :value :logseq.task/status.done}]
+      :actions [[:reschedule :logseq.task/scheduled]
+                [:set-property :logseq.task/status :logseq.task/status.todo]]}]]))
+
+(defn sastify-condition?
+  "Whether entity or updated datoms satisfy the `condition`"
+  [db entity {:keys [property value]} datoms]
+  (when-let [property-entity (d/entity db property)]
+    (let [value-matches? (fn [value]
+                           (cond
+                             (qualified-keyword? value)
+                             (= (:db/ident (get entity property)) value)
+                           ;; ref type
+                             (and (int? value) (contains? db-property-type/all-ref-property-types (:type (:block/schema property-entity))))
+                             (= (:db/id (get entity property)) value)
+                             :else
+                             (= (get entity property) value)))]
+      (if datoms
+        (some (fn [d] (value-matches? (:v d))) datoms)
+        (value-matches? value)))))
+
+(defmulti handle-command (fn [action-id & _others] action-id))
+
+(defmethod handle-command :reschedule [_ entity property]
+  (let [frequency (db-property/property-value-content  (:logseq.task/recur-frequency entity))
+        unit (:logseq.task/recur-unit entity)]
+    (when (and frequency unit)
+      (let [interval (case (:db/ident unit)
+                       :logseq.task/recur-unit.minute t/minutes
+                       :logseq.task/recur-unit.hour t/hours
+                       :logseq.task/recur-unit.day t/days
+                       :logseq.task/recur-unit.week t/weeks
+                       :logseq.task/recur-unit.month t/months
+                       :logseq.task/recur-unit.year t/years)
+            next-time (tc/to-long (t/plus (t/now) (interval frequency)))]
+        [[:db/add (:db/id entity) property next-time]]))))
+
+(defmethod handle-command :set-property [_ entity property value]
+  [[:db/add (:db/id entity) property value]])
+
+(defn execute-command
+  "Build tx-data"
+  [entity [_command {:keys [actions]}]]
+  (mapcat (fn [action]
+            (apply handle-command (first action) entity (rest action))) actions))
+
+(defn run-commands
+  [{:keys [tx-data db-after]}]
+  (let [db db-after]
+    (mapcat (fn [[e datoms]]
+              (let [entity (d/entity db e)
+                    commands (filter (fn [[_command {:keys [entity-conditions tx-conditions]}]]
+                                       (and (every? #(sastify-condition? db entity % nil) entity-conditions)
+                                            (every? #(sastify-condition? db entity % datoms) tx-conditions))) @*commands)]
+                (mapcat
+                 (fn [command]
+                   (execute-command entity command))
+                 commands)))
+            (group-by :e tx-data))))

+ 1 - 2
src/main/frontend/worker/db/migrate.cljs

@@ -16,8 +16,7 @@
             [logseq.common.uuid :as common-uuid]
             [clojure.string :as string]
             [logseq.db.frontend.content :as db-content]
-            [logseq.common.util.page-ref :as page-ref]
-            [logseq.outliner.property :as outliner-property]))
+            [logseq.common.util.page-ref :as page-ref]))
 
 ;; TODO: fixes/rollback
 ;; Frontend migrations

+ 8 - 4
src/main/frontend/worker/pipeline.cljs

@@ -12,7 +12,8 @@
             [logseq.db.sqlite.util :as sqlite-util]
             [logseq.outliner.core :as outliner-core]
             [logseq.outliner.datascript-report :as ds-report]
-            [logseq.outliner.pipeline :as outliner-pipeline]))
+            [logseq.outliner.pipeline :as outliner-pipeline]
+            [frontend.worker.commands :as commands]))
 
 (defn- refs-need-recalculated?
   [tx-meta]
@@ -142,21 +143,24 @@ default = false")
                        (rebuild-block-refs repo tx-report* blocks'))
           refs-tx-report (when (seq block-refs)
                            (ldb/transact! conn block-refs {:pipeline-replace? true}))
+          commands-tx (commands/run-commands tx-report)
           replace-tx (concat
-                          ;; block path refs
+                      ;; block path refs
                       (when (seq blocks')
                         (let [db-after (or (:db-after refs-tx-report) (:db-after tx-report*))
                               blocks' (keep (fn [b] (d/entity db-after (:db/id b))) blocks')]
                           (compute-block-path-refs-tx tx-report* blocks')))
 
-                          ;; update block/tx-id
+                       ;; update block/tx-id
                       (let [updated-blocks (remove (fn [b] (contains? (set deleted-block-uuids) (:block/uuid b)))
                                                    (concat pages blocks))
                             tx-id (get-in (or refs-tx-report tx-report*) [:tempids :db/current-tx])]
                         (keep (fn [b]
                                 (when-let [db-id (:db/id b)]
                                   {:db/id db-id
-                                   :block/tx-id tx-id})) updated-blocks)))
+                                   :block/tx-id tx-id})) updated-blocks))
+
+                      commands-tx)
           tx-report' (if (seq replace-tx)
                        (ldb/transact! conn replace-tx {:pipeline-replace? true})
                        (do