mirror of
https://github.com/penpot/penpot.git
synced 2025-02-13 02:28:18 -05:00
🚧 Initial work on ops based page data updates.
This commit is contained in:
parent
5b96e1e9fd
commit
db768f356b
5 changed files with 94 additions and 44 deletions
|
@ -68,7 +68,7 @@ CREATE TABLE IF NOT EXISTS project_pages (
|
|||
metadata bytea NULL DEFAULT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS project_page_history (
|
||||
CREATE TABLE IF NOT EXISTS project_page_snapshots (
|
||||
id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
|
||||
user_id uuid NULL REFERENCES users(id) ON DELETE SET NULL,
|
||||
|
@ -81,7 +81,8 @@ CREATE TABLE IF NOT EXISTS project_page_history (
|
|||
pinned bool NOT NULL DEFAULT false,
|
||||
label text NOT NULL DEFAULT '',
|
||||
|
||||
data bytea NOT NULL
|
||||
data bytea NOT NULL,
|
||||
operations bytea NULL DEFAULT NULL
|
||||
);
|
||||
|
||||
-- Indexes
|
||||
|
@ -94,8 +95,8 @@ CREATE INDEX project_files__project_id__idx ON project_files(project_id);
|
|||
CREATE INDEX project_pages__user_id__idx ON project_pages(user_id);
|
||||
CREATE INDEX project_pages__file_id__idx ON project_pages(file_id);
|
||||
|
||||
CREATE INDEX project_page_history__page_id__idx ON project_page_history(page_id);
|
||||
CREATE INDEX project_page_history__user_id__idx ON project_page_history(user_id);
|
||||
CREATE INDEX project_page_snapshots__page_id__idx ON project_page_snapshots(page_id);
|
||||
CREATE INDEX project_page_snapshots__user_id__idx ON project_page_snapshots(user_id);
|
||||
|
||||
-- Triggers
|
||||
|
||||
|
@ -152,6 +153,6 @@ CREATE TRIGGER project_pages__modified_at__tgr
|
|||
BEFORE UPDATE ON project_pages
|
||||
FOR EACH ROW EXECUTE PROCEDURE update_modified_at();
|
||||
|
||||
CREATE TRIGGER project_page_history__modified_at__tgr
|
||||
BEFORE UPDATE ON project_page_history
|
||||
CREATE TRIGGER project_page_snapshots__modified_at__tgr
|
||||
BEFORE UPDATE ON project_page_snapshots
|
||||
FOR EACH ROW EXECUTE PROCEDURE update_modified_at();
|
||||
|
|
|
@ -56,11 +56,11 @@
|
|||
(-> (db/query-one conn [sql id user file-id name ordering data mdata])
|
||||
(p/then' decode-row))))
|
||||
|
||||
;; --- Mutation: Update Page
|
||||
;; --- Mutation: Update Page Data
|
||||
|
||||
(declare select-page-for-update)
|
||||
(declare update-page)
|
||||
(declare update-history)
|
||||
(declare update-page-data)
|
||||
(declare insert-page-snapshot)
|
||||
|
||||
(s/def ::update-project-page-data
|
||||
(s/keys :req-un [::id ::user ::data]))
|
||||
|
@ -73,13 +73,13 @@
|
|||
(let [data (blob/encode data)
|
||||
version (inc version)
|
||||
params (assoc params :id id :data data :version version)]
|
||||
(p/do! (update-page conn params)
|
||||
(update-history conn params)
|
||||
(p/do! (update-page-data conn params)
|
||||
(insert-page-snapshot conn params)
|
||||
(select-keys params [:id :version]))))))
|
||||
|
||||
(defn- select-page-for-update
|
||||
[conn id]
|
||||
(let [sql "select p.id, p.version, p.file_id
|
||||
(let [sql "select p.id, p.version, p.file_id, p.data
|
||||
from project_pages as p
|
||||
where p.id = $1
|
||||
and deleted_at is null
|
||||
|
@ -87,8 +87,8 @@
|
|||
(-> (db/query-one conn [sql id])
|
||||
(p/then' su/raise-not-found-if-nil))))
|
||||
|
||||
(defn- update-page
|
||||
[conn {:keys [id name version data metadata]}]
|
||||
(defn- update-page-data
|
||||
[conn {:keys [id name version data]}]
|
||||
(let [sql "update project_pages
|
||||
set version = $1,
|
||||
data = $2
|
||||
|
@ -96,12 +96,12 @@
|
|||
(-> (db/query-one conn [sql version data id])
|
||||
(p/then' su/constantly-nil))))
|
||||
|
||||
(defn- update-history
|
||||
[conn {:keys [user id version data]}]
|
||||
(let [sql "insert into project_page_history (user_id, page_id, version, data)
|
||||
values ($1, $2, $3, $4)"]
|
||||
(-> (db/query-one conn [sql user id version data])
|
||||
(p/then' su/constantly-nil))))
|
||||
(defn- insert-page-snapshot
|
||||
[conn {:keys [user id version data operations]}]
|
||||
(let [sql "insert into project_page_snapshots (user_id, page_id, version, data, operations)
|
||||
values ($1, $2, $3, $4, $5)
|
||||
returning id, version, operations"]
|
||||
(db/query-one conn [sql user id version data operations])))
|
||||
|
||||
;; --- Mutation: Rename Page
|
||||
|
||||
|
@ -126,23 +126,60 @@
|
|||
(-> (db/query-one db/pool [sql id name])
|
||||
(p/then su/constantly-nil))))
|
||||
|
||||
;; --- Mutation: Update Page Metadata
|
||||
;; --- Mutation: Update Page
|
||||
|
||||
;; (s/def ::update-page-metadata
|
||||
;; (s/keys :req-un [::user ::project-id ::name ::metadata ::id]))
|
||||
;; A generic, Ops based (granular) page update method.
|
||||
|
||||
;; (sm/defmutation ::update-page-metadata
|
||||
;; [{:keys [id user project-id name metadata]}]
|
||||
;; (let [sql "update pages
|
||||
;; set name = $3,
|
||||
;; metadata = $4
|
||||
;; where id = $1
|
||||
;; and user_id = $2
|
||||
;; and deleted_at is null
|
||||
;; returning *"
|
||||
;; mdata (blob/encode metadata)]
|
||||
;; (-> (db/query-one db/pool [sql id user name mdata])
|
||||
;; (p/then' decode-row))))
|
||||
(s/def ::operations
|
||||
(s/coll-of ::cp/opeation :kind vector?))
|
||||
|
||||
(s/def ::update-project-page
|
||||
(s/keys :opt-un [::id ::user ::version ::operations]))
|
||||
|
||||
(declare update-project-page)
|
||||
(declare retrieve-lagged-operations)
|
||||
|
||||
(sm/defmutation ::update-project-page
|
||||
[{:keys [id user] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(p/let [{:keys [file-id] :as page} (select-page-for-update conn id)]
|
||||
(files/check-edition-permissions! conn user file-id)
|
||||
(update-project-page conn page params))))
|
||||
|
||||
(defn- update-project-page
|
||||
[conn page params]
|
||||
(when (> (:version page)
|
||||
(:version params))
|
||||
(ex/raise :type :validation
|
||||
:code :version-conflict
|
||||
:hint "The incoming version is greater that stored version."
|
||||
:context {:incoming-version (:version params)
|
||||
:stored-version (:version page)}))
|
||||
(let [ops (:operations params)
|
||||
data (-> (:data page)
|
||||
(blob/decode)
|
||||
(cp/process-ops ops)
|
||||
(blob/encode))
|
||||
page (assoc page
|
||||
:data data
|
||||
:version (inc (:version page))
|
||||
:operations (blob/encode ops))]
|
||||
(-> (update-page-data conn page)
|
||||
(p/then (fn [_] (insert-page-snapshot conn page)))
|
||||
(p/then (fn [s] (retrieve-lagged-operations conn s params))))))
|
||||
|
||||
(su/defstr sql:lagged-snapshots
|
||||
"select s.id, s.version, s.operations,
|
||||
s.created_at, s.modified_at, s.user_id
|
||||
from project_page_snapshots as s
|
||||
where s.page_id = $1
|
||||
and s.version > $2")
|
||||
|
||||
(defn- retrieve-lagged-operations
|
||||
[conn snapshot params]
|
||||
(let [sql sql:lagged-snapshots]
|
||||
(-> (db/query conn [sql (:id params) (:version params)])
|
||||
(p/then (partial mapv decode-row)))))
|
||||
|
||||
;; --- Mutation: Delete Page
|
||||
|
||||
|
@ -158,12 +195,15 @@
|
|||
(files/check-edition-permissions! conn user (:file-id page))
|
||||
(delete-page conn id))))
|
||||
|
||||
(su/defstr sql:delete-page
|
||||
"update project_pages
|
||||
set deleted_at = clock_timestamp()
|
||||
where id = $1
|
||||
and deleted_at is null")
|
||||
|
||||
(defn- delete-page
|
||||
[conn id]
|
||||
(let [sql "update project_pages
|
||||
set deleted_at = clock_timestamp()
|
||||
where id = $1
|
||||
and deleted_at is null"]
|
||||
(let [sql sql:delete-page]
|
||||
(-> (db/query-one conn [sql id])
|
||||
(p/then su/constantly-nil))))
|
||||
|
||||
|
@ -178,7 +218,7 @@
|
|||
;; (some-> (db/fetch-one conn sqlv)
|
||||
;; (decode-row))))
|
||||
|
||||
;; (s/def ::label ::us/string)
|
||||
;; (s/def ::label ::cs/string)
|
||||
;; (s/def ::update-page-history
|
||||
;; (s/keys :req-un [::user ::id ::pinned ::label]))
|
||||
|
||||
|
|
|
@ -139,8 +139,9 @@
|
|||
;; --- Helpers
|
||||
|
||||
(defn decode-row
|
||||
[{:keys [data metadata] :as row}]
|
||||
[{:keys [data metadata operations] :as row}]
|
||||
(when row
|
||||
(cond-> row
|
||||
data (assoc :data (blob/decode data))
|
||||
metadata (assoc :metadata (blob/decode metadata)))))
|
||||
metadata (assoc :metadata (blob/decode metadata))
|
||||
operations (assoc :operations (blob/decode operations)))))
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
[uxbox.http :as http]
|
||||
[uxbox.services.mutations :as sm]
|
||||
[uxbox.services.queries :as sq]
|
||||
[uxbox.util.uuid :as uuid]
|
||||
[uxbox.tests.helpers :as th]))
|
||||
|
||||
(t/use-fixtures :once th/state-init)
|
||||
|
@ -34,7 +35,9 @@
|
|||
pf @(th/create-project-file db/pool (:id user) (:id proj) 1)
|
||||
|
||||
data {::sm/type :create-project-page
|
||||
:data {}
|
||||
:data {:canvas []
|
||||
:shapes []
|
||||
:shapes-by-id {}}
|
||||
:metadata {}
|
||||
:file-id (:id pf)
|
||||
:ordering 1
|
||||
|
@ -57,7 +60,9 @@
|
|||
page @(th/create-project-page db/pool (:id user) (:id file) 1)
|
||||
data {::sm/type :update-project-page-data
|
||||
:id (:id page)
|
||||
:data {:shapes [1 2 3]}
|
||||
:data {:shapes [(uuid/next)]
|
||||
:canvas []
|
||||
:shapes-by-id {}}
|
||||
:file-id (:id file)
|
||||
:user (:id user)}
|
||||
out (th/try-on! (sm/handle data))]
|
||||
|
|
|
@ -82,6 +82,9 @@
|
|||
"A marker protocol for mark events that alters the
|
||||
page and is subject to perform a backend synchronization.")
|
||||
|
||||
(defprotocol IPageOps
|
||||
(-ops [_] "Get a list of ops for the event."))
|
||||
|
||||
(defn page-update?
|
||||
[o]
|
||||
(or (satisfies? IPageDataUpdate o)
|
||||
|
|
Loading…
Add table
Reference in a new issue