0
Fork 0
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:
Andrey Antukh 2019-12-14 21:24:38 +01:00
parent 5b96e1e9fd
commit db768f356b
5 changed files with 94 additions and 44 deletions

View file

@ -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();

View file

@ -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]))

View file

@ -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)))))

View file

@ -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))]

View file

@ -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)