mirror of
https://github.com/penpot/penpot.git
synced 2026-11-08 11:04:44 +00:00
Partition `file_change` by `HASH (file_id)` in 16 partitions, with the same bounds as `file_data`, so a join between them is resolved partition by partition. The primary key becomes `(file_id, id)`, which a partitioned table needs, and every access filters by `file_id`. The new table carries a `kind` column (1 snapshot, 2 revision) as a reserve: the queries still tell them apart by the label, and `kind` takes over when they are rewritten. The payload of a snapshot stays in `file_data`; the `data` column is kept for reading old `legacy-db` payloads. The four snapshot commands require `file-id`, because it prunes the partition. The objects GC locks and deletes by the pair, in batches. The old table is kept as `file_change_legacy` as the way back. The automatic migration refuses to run above 10 GiB or 2M rows and points to the runbook; big instances partition online with that runbook, which copies by id, follows the `updated_at` watermark in delta passes and checks that no row of the source is missing from the target. Closes #12416 AI-assisted-by: deepseek-v4.1-flash
117 lines
4.7 KiB
Clojure
117 lines
4.7 KiB
Clojure
;; This Source Code Form is subject to the terms of the Mozilla Public
|
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
;;
|
|
;; Copyright (c) KALEIDOS SUBSIDIARY SL
|
|
|
|
(ns frontend-tests.plugins.file-test
|
|
(:require
|
|
[app.common.time :as ct]
|
|
[app.common.uuid :as uuid]
|
|
[app.main.repo :as rp]
|
|
[app.plugins.file :as file]
|
|
[app.plugins.register :as r]
|
|
[beicon.v2.core :as rx]
|
|
[cljs.test :as t :include-macros true]
|
|
[frontend-tests.helpers.mock :as mock]))
|
|
|
|
(t/deftest file-version-created-at-returns-stored-date
|
|
(let [created-at (js/Date.)
|
|
version (file/file-version-proxy
|
|
"00000000-0000-0000-0000-000000000000"
|
|
(random-uuid)
|
|
{}
|
|
{:id (random-uuid)
|
|
:label "Version"
|
|
:created-at created-at})]
|
|
(t/is (identical? created-at (.-createdAt version)))))
|
|
|
|
(defn- make-version
|
|
[file-id data]
|
|
(file/file-version-proxy (str (uuid/next)) file-id {} data))
|
|
|
|
(defn- record-cmd!
|
|
"Mock for `rp/cmd!` that records the calls and answers an observable with
|
|
the shape each command expects: a list of team users, and `true` for the
|
|
snapshot update (`update-file-snapshot` answers a boolean)."
|
|
[calls]
|
|
(fn [cmd params]
|
|
(swap! calls conj [cmd params])
|
|
(rx/of (if (= :get-team-users cmd) [] true))))
|
|
|
|
(t/deftest ^:async file-version-proxy-sends-the-file-id
|
|
;; The snapshot RPC commands require the `file-id` (they need it for the
|
|
;; partition pruning on `file_change`); the plugin proxy is the other door to
|
|
;; them and has to send it on rename, remove and pin.
|
|
(let [file-id (uuid/next)
|
|
version-id (uuid/next)
|
|
calls (atom [])]
|
|
|
|
(await
|
|
(mock/with-mocks*
|
|
{r/check-permission (constantly true)
|
|
rp/cmd! (mock/stub (record-cmd! calls))}
|
|
|
|
(t/testing "rename sends the file id"
|
|
(reset! calls [])
|
|
(let [version (make-version file-id
|
|
{:id version-id
|
|
:label "Version"
|
|
:created-at (ct/now)
|
|
:created-by "user"})]
|
|
(aset version "label" "renamed")
|
|
(let [[cmd params] (last @calls)]
|
|
(t/is (= :update-file-snapshot cmd))
|
|
(t/is (= file-id (:file-id params)))
|
|
(t/is (= "renamed" (:label params))))))
|
|
|
|
(t/testing "remove sends the file id"
|
|
(reset! calls [])
|
|
(let [version (make-version file-id
|
|
{:id version-id
|
|
:label "Version"
|
|
:created-at (ct/now)
|
|
:created-by "user"})]
|
|
(await (.remove version))
|
|
(let [[cmd params] (last @calls)]
|
|
(t/is (= :delete-file-snapshot cmd))
|
|
(t/is (= file-id (:file-id params))))))
|
|
|
|
(t/testing "pin sends the file id on both commands"
|
|
(reset! calls [])
|
|
(let [version (make-version file-id
|
|
{:id version-id
|
|
:label "Version"
|
|
:created-at (ct/now)
|
|
:created-by "system"})]
|
|
(await (.pin version))
|
|
(t/is (= [[:get-team-users file-id]
|
|
[:update-file-snapshot file-id]]
|
|
(mapv (fn [[cmd params]] [cmd (:file-id params)]) @calls)))))))))
|
|
|
|
(t/deftest ^:async file-version-proxy-pin-resolves-the-pinned-version
|
|
;; `pin` answers with a proxy, not with the boolean the snapshot command
|
|
;; returns: the autosave becomes a user version with a new label.
|
|
(let [file-id (uuid/next)
|
|
version-id (uuid/next)
|
|
created-at (ct/now)
|
|
calls (atom [])]
|
|
(await
|
|
(mock/with-mocks*
|
|
{r/check-permission (constantly true)
|
|
rp/cmd! (mock/stub (record-cmd! calls))}
|
|
(let [version (make-version file-id
|
|
{:id version-id
|
|
:label "Version"
|
|
:created-at created-at
|
|
:created-by "system"})
|
|
pinned (await (.pin version))]
|
|
(t/is (file/file-version-proxy? pinned))
|
|
(t/is (= [[:get-team-users file-id]
|
|
[:update-file-snapshot file-id]]
|
|
(mapv (fn [[cmd params]] [cmd (:file-id params)]) @calls)))
|
|
(t/is (= (ct/format-inst created-at :localized-date)
|
|
(.-label pinned)))
|
|
(t/is (false? (.-isAutosave pinned)))
|
|
(t/is (identical? created-at (.-createdAt pinned))))))))
|