diff --git a/deps/db/src/logseq/db/frontend/property.cljs b/deps/db/src/logseq/db/frontend/property.cljs index 5bd8aa0a6b..e7036e7647 100644 --- a/deps/db/src/logseq/db/frontend/property.cljs +++ b/deps/db/src/logseq/db/frontend/property.cljs @@ -38,6 +38,7 @@ (def ^:large-vars/data-var built-in-properties* "Map of built in properties for db graphs with their :db/ident as keys. Each property has a config map with the following keys: + TODO: Move some of these keys to :properties since :schema is a deprecated concept * :schema - Property's schema. Required key. Has the following common keys: * :type - Property type * :cardinality - property cardinality. Default to one/single cardinality if not set @@ -599,12 +600,23 @@ "Property values that shouldn't be updated" #{:logseq.property/built-in?}) +(def schema-properties-map + "Maps schema unqualified keywords to their qualified keywords. + The qualified keywords are all properties except for :db/cardinality + which is a datascript attribute" + {:cardinality :db/cardinality + :type :logseq.property/type + :hide? :logseq.property/hide? + :public? :logseq.property/public? + :ui-position :logseq.property/ui-position + :view-context :logseq.property/view-context + :classes :logseq.property/classes}) + (def schema-properties "Properties that used to be in block/schema. Schema originally referred to just type and cardinality but expanded to include a property's core configuration because it was easy to add to the schema map. - We should move some of these out since they are just like any other properties e.g. view-context" - #{:db/cardinality :logseq.property/type :logseq.property/hide? :logseq.property/public? - :logseq.property/view-context :logseq.property/ui-position :logseq.property/classes}) + We should move some of these out since they are just like any other properties e.g. :view-context" + (set (vals schema-properties-map))) (def logseq-property-namespaces #{"logseq.property" "logseq.property.tldraw" "logseq.property.pdf" "logseq.property.fsrs" "logseq.task" diff --git a/deps/db/src/logseq/db/sqlite/create_graph.cljs b/deps/db/src/logseq/db/sqlite/create_graph.cljs index d648f7e976..d6b8820c60 100644 --- a/deps/db/src/logseq/db/sqlite/create_graph.cljs +++ b/deps/db/src/logseq/db/sqlite/create_graph.cljs @@ -44,15 +44,16 @@ (fn [[db-ident {:keys [attribute schema title closed-values properties] :as m}]] (let [db-ident (or attribute db-ident) prop-name (or title (name (:name m))) + schema' (sqlite-util/schema->qualified-property-keyword schema) [property & others] (if closed-values (db-property-build/build-closed-values db-ident prop-name - {:db/ident db-ident :schema schema :closed-values closed-values} + {:db/ident db-ident :schema schema' :closed-values closed-values} {}) [(sqlite-util/build-new-property db-ident - schema + schema' {:title prop-name})]) pvalue-tx-m (->property-value-tx-m (merge property @@ -86,7 +87,7 @@ [db-ident] (sqlite-util/build-new-property db-ident - (get-in db-property/built-in-properties [db-ident :schema]) + (sqlite-util/schema->qualified-property-keyword (get-in db-property/built-in-properties [db-ident :schema])) {:title (get-in db-property/built-in-properties [db-ident :title])})) (defn- build-initial-properties diff --git a/deps/db/src/logseq/db/sqlite/util.cljs b/deps/db/src/logseq/db/sqlite/util.cljs index 2903b1ae8b..11e67c0d18 100644 --- a/deps/db/src/logseq/db/sqlite/util.cljs +++ b/deps/db/src/logseq/db/sqlite/util.cljs @@ -70,17 +70,9 @@ [prop-schema] (reduce-kv (fn [r k v] - (if (qualified-keyword? k) - (assoc r k v) - (cond - (= k :cardinality) - (assoc r :db/cardinality v) - (= k :classes) - (assoc r :logseq.property/classes v) - (= k :position) - (assoc r :logseq.property/ui-position v) - :else - (assoc r (keyword "logseq.property" k) v)))) + (if-let [new-k (and (simple-keyword? k) (db-property/schema-properties-map k))] + (assoc r new-k v) + (assoc r k v))) {} prop-schema)) @@ -90,13 +82,12 @@ * :title - Case sensitive property name. Defaults to deriving this from db-ident * :block-uuid - :block/uuid for property" ([db-ident prop-schema] (build-new-property db-ident prop-schema {})) - ([db-ident prop-schema' {:keys [title block-uuid ref-type? properties]}] + ([db-ident prop-schema {:keys [title block-uuid ref-type? properties]}] (assert (keyword? db-ident)) (let [db-ident' (if (qualified-keyword? db-ident) db-ident (db-property/create-user-property-ident-from-name (name db-ident))) prop-name (or title (name db-ident')) - prop-schema (schema->qualified-property-keyword prop-schema') prop-type (get prop-schema :logseq.property/type :default)] (merge (dissoc prop-schema :db/cardinality) diff --git a/deps/graph-parser/src/logseq/graph_parser/exporter.cljs b/deps/graph-parser/src/logseq/graph_parser/exporter.cljs index 64e9088276..64d61803e6 100644 --- a/deps/graph-parser/src/logseq/graph_parser/exporter.cljs +++ b/deps/graph-parser/src/logseq/graph_parser/exporter.cljs @@ -370,7 +370,7 @@ (defn- infer-property-schema-and-get-property-change "Infers a property's schema from the given _user_ property value and adds new ones to - the property-schemas atom. If a property's :type changes, returns a map of + the property-schemas atom. If a property's :logseq.property/type changes, returns a map of the schema attribute changed and how it changed e.g. `{:type {:from :default :to :url}}`" [db prop-val prop prop-val-text refs {:keys [property-schemas all-idents]} macros] ;; Explicitly fail an unexpected case rather than cause silent downstream failures @@ -390,15 +390,15 @@ :else (db-property-type/infer-property-type-from-value (macro-util/expand-value-if-macro prop-val macros))) - prev-type (get-in @property-schemas [prop :type])] + prev-type (get-in @property-schemas [prop :logseq.property/type])] ;; Create new property (when-not (get @property-schemas prop) (create-property-ident db all-idents prop) - (let [schema (cond-> {:type prop-type} + (let [schema (cond-> {:logseq.property/type prop-type} (#{:node :date} prop-type) ;; Assume :many for now as detecting that detecting property values across files are consistent ;; isn't possible yet - (assoc :cardinality :many))] + (assoc :db/cardinality :many))] (swap! property-schemas assoc prop schema))) (when (and prev-type (not= prev-type prop-type)) {:type {:from prev-type :to prop-type}}))) @@ -555,7 +555,7 @@ ;; Change to :node as dates can be pages but pages can't be dates (= {:from :date :to :node} type-change) (do - (swap! property-schemas assoc-in [prop :type] :node) + (swap! property-schemas assoc-in [prop :logseq.property/type] :node) (update-page-or-date-values page-names-to-uuids val)) ;; Unlike the other property changes, this one changes all the previous values of a property @@ -568,9 +568,9 @@ (swap! ignored-properties conj {:property prop :value val :schema (get property-changes prop)}) nil) (do - (swap! upstream-properties assoc prop {:schema {:type :default} + (swap! upstream-properties assoc prop {:schema {:logseq.property/type :default} :from-type (:from type-change)}) - (swap! property-schemas assoc prop {:type :default}) + (swap! property-schemas assoc prop {:logseq.property/type :default}) (get properties-text-values prop))) :else @@ -590,7 +590,7 @@ [prop val']) [prop (if (set? val) - (if (= :default (:type (get @property-schemas prop))) + (if (= :default (:logseq.property/type (get @property-schemas prop))) (get properties-text-values prop) (update-page-or-date-values page-names-to-uuids val)) val)]))) @@ -609,12 +609,11 @@ (let [property-map {:db/ident k :logseq.property/type built-in-type}] [property-map v])) - (when (db-property-type/value-ref-property-types (:type (get-schema-fn k))) - (let [schema (get-schema-fn k) - property-map (merge + (when (db-property-type/value-ref-property-types (:logseq.property/type (get-schema-fn k))) + (let [property-map (merge {:db/ident (get-ident all-idents k) :original-property-id k} - (sqlite-util/schema->qualified-property-keyword schema))] + (get-schema-fn k))] [property-map v]))))) (db-property-build/build-property-values-tx-m new-block))) @@ -1095,11 +1094,9 @@ (fn [[prop {:keys [schema from-type]}]] (let [prop-ident (get-ident all-idents prop) upstream-tx - (when (= :default (:type schema)) + (when (= :default (:logseq.property/type schema)) (build-upstream-properties-tx-for-default db prop prop-ident from-type block-properties-text-values)) - property-pages-tx [(merge - {:db/ident prop-ident} - (sqlite-util/schema->qualified-property-keyword schema))]] + property-pages-tx [(merge {:db/ident prop-ident} schema)]] ;; If we handle cardinality changes we would need to return these separately ;; as property-pages would need to be transacted separately (concat property-pages-tx upstream-tx))) @@ -1117,7 +1114,7 @@ :ignored-properties (atom []) ;; Vec of maps with keys :path and :reason :ignored-files (atom []) - ;; Map of property names (keyword) and their current schemas (map). + ;; Map of property names (keyword) and their current schemas (map of qualified properties). ;; Used for adding schemas to properties and detecting changes across a property's usage :property-schemas (atom {}) ;; Map of property or class names (keyword) to db-ident keywords diff --git a/deps/outliner/src/logseq/outliner/property.cljs b/deps/outliner/src/logseq/outliner/property.cljs index e91afba0ca..87413950bb 100644 --- a/deps/outliner/src/logseq/outliner/property.cljs +++ b/deps/outliner/src/logseq/outliner/property.cljs @@ -158,8 +158,7 @@ (throw (ex-info (str e) {:type :notification :payload {:message "Property failed to create. Please try a different property name." - :type :error}}))))) - schema (sqlite-util/schema->qualified-property-keyword schema)] + :type :error}})))))] (assert (qualified-keyword? db-ident)) (if-let [property (and (qualified-keyword? property-id) (d/entity db db-ident))] (update-property conn db-ident property schema opts) diff --git a/deps/outliner/test/logseq/outliner/property_test.cljs b/deps/outliner/test/logseq/outliner/property_test.cljs index da18cee65e..e1f1fd8c4a 100644 --- a/deps/outliner/test/logseq/outliner/property_test.cljs +++ b/deps/outliner/test/logseq/outliner/property_test.cljs @@ -9,7 +9,7 @@ (deftest upsert-property! (testing "Creates a property" (let [conn (db-test/create-conn-with-blocks []) - _ (outliner-property/upsert-property! conn nil {:type :number} {:property-name "num"})] + _ (outliner-property/upsert-property! conn nil {:logseq.property/type :number} {:property-name "num"})] (is (= :number (:logseq.property/type (d/entity @conn :user.property/num))) "Creates property with property-name"))) @@ -19,19 +19,19 @@ old-updated-at (:block/updated-at (d/entity @conn :user.property/num))] (testing "and change its cardinality" - (outliner-property/upsert-property! conn :user.property/num {:cardinality :many} {}) + (outliner-property/upsert-property! conn :user.property/num {:db/cardinality :many} {}) (is (db-property/many? (d/entity @conn :user.property/num))) (is (> (:block/updated-at (d/entity @conn :user.property/num)) old-updated-at))) (testing "and change its type from a ref to a non-ref type" - (outliner-property/upsert-property! conn :user.property/num {:type :checkbox} {}) + (outliner-property/upsert-property! conn :user.property/num {:logseq.property/type :checkbox} {}) (is (= :checkbox (:logseq.property/type (d/entity @conn :user.property/num)))) (is (= nil (:db/valueType (d/entity @conn :user.property/num))))))) (testing "Multiple properties that generate the same initial :db/ident" (let [conn (db-test/create-conn-with-blocks [])] - (outliner-property/upsert-property! conn nil {:type :default} {:property-name "p1"}) + (outliner-property/upsert-property! conn nil {:logseq.property/type :default} {:property-name "p1"}) (outliner-property/upsert-property! conn nil {} {:property-name "p1"}) (outliner-property/upsert-property! conn nil {} {:property-name "p1"}) diff --git a/src/main/frontend/components/property/config.cljs b/src/main/frontend/components/property/config.cljs index cbb8b73b3f..ef9ae55735 100644 --- a/src/main/frontend/components/property/config.cljs +++ b/src/main/frontend/components/property/config.cljs @@ -555,7 +555,7 @@ (p/do! (db-property-handler/upsert-property! (:db/ident property) - {:type (keyword v)} + {:logseq.property/type (keyword v)} {}) (set-sub-open! false) (restore-root-highlight-item! id)))) @@ -660,7 +660,7 @@ :on-toggle-checked-change (fn [] (let [update-cardinality-fn #(db-property-handler/upsert-property! (:db/ident property) - {:cardinality (if many? :one :many)} + {:db/cardinality (if many? :one :many)} {})] ;; Only show dialog for existing values as it can be reversed for unused properties (if (and (seq values) (not many?)) diff --git a/src/main/frontend/worker/db/migrate.cljs b/src/main/frontend/worker/db/migrate.cljs index 7b7a28c402..7cd6a889c6 100644 --- a/src/main/frontend/worker/db/migrate.cljs +++ b/src/main/frontend/worker/db/migrate.cljs @@ -534,6 +534,24 @@ [:db/retract e :logseq.user/avatar]]) db-ids)))))) +(defn- schema->qualified-property-keyword + [prop-schema] + (reduce-kv + (fn [r k v] + (if (qualified-keyword? k) + (assoc r k v) + (cond + (= k :cardinality) + (assoc r :db/cardinality v) + (= k :classes) + (assoc r :logseq.property/classes v) + (= k :position) + (assoc r :logseq.property/ui-position v) + :else + (assoc r (keyword "logseq.property" k) v)))) + {} + prop-schema)) + (defn- remove-block-schema [conn _search-db] (let [db @conn @@ -546,7 +564,7 @@ tx-data (mapcat (fn [eid] (let [entity (d/entity db eid) schema (:block/schema entity) - schema-properties (sqlite-util/schema->qualified-property-keyword schema) + schema-properties (schema->qualified-property-keyword schema) hidden-page? (contains? #{common-config/favorites-page-name common-config/views-page-name} (:block/title entity)) m (assoc schema-properties :db/id eid)