mirror of
https://github.com/penpot/penpot.git
synced 2025-06-05 11:01:41 +02:00
♻️ Refactor images storage.
This commit is contained in:
parent
b98d8519d4
commit
2cebbbc2f8
34 changed files with 2032 additions and 1630 deletions
|
@ -21,38 +21,14 @@
|
|||
[uxbox.util.uuid :as uuid]
|
||||
[vertx.core :as vc]))
|
||||
|
||||
(def +thumbnail-options+
|
||||
{:src :path
|
||||
:dst :thumbnail
|
||||
:width 300
|
||||
:height 100
|
||||
:quality 92
|
||||
:format "webp"})
|
||||
|
||||
(defn populate-thumbnail
|
||||
[row]
|
||||
(let [opts +thumbnail-options+]
|
||||
(-> (p/promise row)
|
||||
(p/then (vc/wrap-blocking #(images/populate-thumbnail % opts))))))
|
||||
|
||||
(defn populate-thumbnails
|
||||
[rows]
|
||||
(if (empty? rows)
|
||||
rows
|
||||
(vc/blocking
|
||||
(mapv (fn [row]
|
||||
(images/populate-thumbnail row +thumbnail-options+)) rows))))
|
||||
|
||||
(defn populate-urls
|
||||
[row]
|
||||
(images/populate-urls row media/images-storage :path :url))
|
||||
|
||||
(s/def ::id ::us/uuid)
|
||||
(s/def ::name ::us/string)
|
||||
(s/def ::user ::us/uuid)
|
||||
(s/def ::collection-id (s/nilable ::us/uuid))
|
||||
|
||||
(def ^:private images-collections-sql
|
||||
;; --- Query: Images Collections
|
||||
|
||||
(def ^:private sql:collections
|
||||
"select *,
|
||||
(select count(*) from images where collection_id = ic.id) as num_images
|
||||
from image_collections as ic
|
||||
|
@ -66,9 +42,10 @@
|
|||
|
||||
(sq/defquery ::images-collections
|
||||
[{:keys [user] :as params}]
|
||||
(db/query db/pool [images-collections-sql user]))
|
||||
(db/query db/pool [sql:collections user]))
|
||||
|
||||
;; --- Retrieve Image
|
||||
|
||||
;; --- Query: Image by ID
|
||||
|
||||
(defn retrieve-image
|
||||
[conn id]
|
||||
|
@ -84,10 +61,10 @@
|
|||
(sq/defquery ::image-by-id
|
||||
[params]
|
||||
(-> (retrieve-image db/pool (:id params))
|
||||
(p/then populate-thumbnail)
|
||||
(p/then populate-urls)))
|
||||
(p/then' #(images/resolve-urls % :path :uri))
|
||||
(p/then' #(images/resolve-urls % :thumb-path :thumb-uri))))
|
||||
|
||||
;; --- Query Images by Collection (id)
|
||||
;; --- Query: Images by collection ID
|
||||
|
||||
(def sql:images-by-collection
|
||||
"select * from images
|
||||
|
@ -96,12 +73,7 @@
|
|||
and deleted_at is null
|
||||
order by created_at desc")
|
||||
|
||||
(def sql:images-by-collection1
|
||||
(str "with images as (" sql:images-by-collection ")
|
||||
select im.* from images as im
|
||||
where im.collection_id is null"))
|
||||
|
||||
(def sql:images-by-collection2
|
||||
(def sql:images-by-collection
|
||||
(str "with images as (" sql:images-by-collection ")
|
||||
select im.* from images as im
|
||||
where im.collection_id = $2"))
|
||||
|
@ -110,12 +82,14 @@
|
|||
(s/keys :req-un [::user]
|
||||
:opt-un [::collection-id]))
|
||||
|
||||
;; TODO: check if we can resolve url with transducer for reduce
|
||||
;; garbage generation for each request
|
||||
|
||||
(sq/defquery ::images-by-collection
|
||||
[{:keys [user collection-id] :as params}]
|
||||
(let [sqlv (if (nil? collection-id)
|
||||
[sql:images-by-collection1 user]
|
||||
[sql:images-by-collection2 user collection-id])]
|
||||
(let [sqlv [sql:images-by-collection user collection-id]]
|
||||
(-> (db/query db/pool sqlv)
|
||||
(p/then populate-thumbnails)
|
||||
(p/then #(mapv populate-urls %)))))
|
||||
|
||||
(p/then' (fn [rows]
|
||||
(->> rows
|
||||
(mapv #(images/resolve-urls % :path :uri))
|
||||
(mapv #(images/resolve-urls % :thumb-path :thumb-uri))))))))
|
||||
|
|
|
@ -31,15 +31,15 @@
|
|||
|
||||
;; --- Query: Profile (own)
|
||||
|
||||
(defn resolve-thumbnail
|
||||
[user]
|
||||
(let [opts {:src :photo
|
||||
:dst :photo
|
||||
:size [100 100]
|
||||
:quality 90
|
||||
:format "jpg"}]
|
||||
(-> (px/submit! #(images/populate-thumbnails user opts))
|
||||
(su/handle-on-context))))
|
||||
;; (defn resolve-thumbnail
|
||||
;; [user]
|
||||
;; (let [opts {:src :photo
|
||||
;; :dst :photo
|
||||
;; :size [100 100]
|
||||
;; :quality 90
|
||||
;; :format "jpg"}]
|
||||
;; (-> (px/submit! #(images/populate-thumbnails user opts))
|
||||
;; (su/handle-on-context))))
|
||||
|
||||
(defn retrieve-profile
|
||||
[conn id]
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
[promesa.core :as p]
|
||||
[uxbox.common.spec :as us]
|
||||
[uxbox.db :as db]
|
||||
[uxbox.images :as images]
|
||||
[uxbox.services.queries :as sq]
|
||||
[uxbox.services.util :as su]
|
||||
[uxbox.util.blob :as blob]))
|
||||
|
@ -27,24 +28,6 @@
|
|||
(s/def ::file-id ::us/uuid)
|
||||
(s/def ::user ::us/uuid)
|
||||
|
||||
(def sql:generic-project-files
|
||||
"select distinct on (pf.id, pf.created_at)
|
||||
pf.*,
|
||||
p.name as project_name,
|
||||
array_agg(pp.id) over pages_w as pages,
|
||||
first_value(pp.data) over pages_w as data
|
||||
from project_files as pf
|
||||
inner join projects as p on (pf.project_id = p.id)
|
||||
inner join project_users as pu on (p.id = pu.project_id)
|
||||
left join project_pages as pp on (pf.id = pp.file_id)
|
||||
where pu.user_id = $1
|
||||
and pu.can_edit = true
|
||||
and pf.deleted_at is null
|
||||
and pp.deleted_at is null
|
||||
window pages_w as (partition by pf.id order by pp.created_at
|
||||
range BETWEEN UNBOUNDED PRECEDING
|
||||
AND UNBOUNDED FOLLOWING)")
|
||||
|
||||
;; --- Query: Project Files
|
||||
|
||||
(declare retrieve-recent-files)
|
||||
|
@ -60,33 +43,77 @@
|
|||
(retrieve-recent-files db/pool params)
|
||||
(retrieve-project-files db/pool params)))
|
||||
|
||||
(def sql:project-files
|
||||
(str "with files as (" sql:generic-project-files ")
|
||||
select * from files where project_id = $2
|
||||
order by created_at asc"))
|
||||
(def ^:private sql:generic-project-files
|
||||
"select distinct
|
||||
pf.*,
|
||||
array_agg(pp.id) over pages_w as pages,
|
||||
first_value(pp.data) over pages_w as data,
|
||||
p.name as project_name
|
||||
from project_users as pu
|
||||
inner join project_files as pf on (pf.project_id = pu.project_id)
|
||||
inner join projects as p on (p.id = pf.project_id)
|
||||
left join project_pages as pp on (pf.id = pp.file_id)
|
||||
where pu.user_id = $1
|
||||
and pu.can_edit = true
|
||||
window pages_w as (partition by pf.id order by pp.created_at
|
||||
range between unbounded preceding
|
||||
and unbounded following)
|
||||
order by pf.created_at")
|
||||
|
||||
(def sql:recent-files
|
||||
(str "with files as (" sql:generic-project-files ")
|
||||
select * from files
|
||||
order by modified_at desc
|
||||
limit $2"))
|
||||
(def ^:private sql:project-files
|
||||
(str "with files as (" sql:generic-project-files ") "
|
||||
"select * from files where project_id = $2"))
|
||||
|
||||
(defn retrieve-project-files
|
||||
[conn {:keys [user project-id]}]
|
||||
(-> (db/query conn [sql:project-files user project-id])
|
||||
(p/then' (partial mapv decode-row))))
|
||||
|
||||
(def ^:private sql:recent-files
|
||||
"with project_files as (
|
||||
(select pf.*,
|
||||
array_agg(pp.id) over pages_w as pages,
|
||||
first_value(pp.data) over pages_w as data,
|
||||
p.name as project_name
|
||||
from project_users as pu
|
||||
inner join project_files as pf on (pf.project_id = pu.project_id)
|
||||
inner join projects as p on (p.id = pf.project_id)
|
||||
left join project_pages as pp on (pf.id = pp.file_id)
|
||||
where pu.user_id = $1
|
||||
and pu.can_edit = true
|
||||
window pages_w as (partition by pf.id order by pp.created_at
|
||||
range between unbounded preceding
|
||||
and unbounded following))
|
||||
union
|
||||
(select pf.*,
|
||||
array_agg(pp.id) over pages_w as pages,
|
||||
first_value(pp.data) over pages_w as data,
|
||||
p.name as project_name
|
||||
from project_file_users as pfu
|
||||
inner join project_files as pf on (pfu.file_id = pf.id)
|
||||
inner join projects as p on (p.id = pf.project_id)
|
||||
left join project_pages as pp on (pf.id = pp.file_id)
|
||||
where pfu.user_id = $1
|
||||
and pfu.can_edit = true
|
||||
window pages_w as (partition by pf.id order by pp.created_at
|
||||
range between unbounded preceding
|
||||
and unbounded following))
|
||||
) select pf1.*
|
||||
from project_files as pf1
|
||||
order by pf1.modified_at desc
|
||||
limit $2;")
|
||||
|
||||
|
||||
(defn retrieve-recent-files
|
||||
[conn {:keys [user]}]
|
||||
(-> (db/query conn [sql:recent-files user 20])
|
||||
(p/then' (partial mapv decode-row))))
|
||||
|
||||
|
||||
;; --- Query: Project File (By ID)
|
||||
|
||||
(def sql:project-file
|
||||
(str "with files as (" sql:generic-project-files ")
|
||||
select * from files where id = $2"))
|
||||
(def ^:private sql:project-file
|
||||
(str "with files as (" sql:generic-project-files ") "
|
||||
"select * from files where id = $2"))
|
||||
|
||||
(s/def ::project-file
|
||||
(s/keys :req-un [::user ::id]))
|
||||
|
@ -96,36 +123,10 @@
|
|||
(-> (db/query-one db/pool [sql:project-file user id])
|
||||
(p/then' decode-row)))
|
||||
|
||||
|
||||
;; --- Query: Users of the File
|
||||
|
||||
(def sql:file-users
|
||||
"select u.id, u.fullname, u.photo
|
||||
from users as u
|
||||
join project_file_users as pfu on (pfu.user_id = u.id)
|
||||
where pfu.file_id = $1
|
||||
union all
|
||||
select u.id, u.fullname, u.photo
|
||||
from users as u
|
||||
join project_users as pu on (pu.user_id = u.id)
|
||||
where pu.project_id = $2")
|
||||
|
||||
(def sql:file-users
|
||||
"select u.id, u.fullname, u.photo
|
||||
from users as u
|
||||
join project_file_users as pfu on (pfu.user_id = u.id)
|
||||
where pfu.file_id = $1
|
||||
union all
|
||||
select u.id, u.fullname, u.photo
|
||||
from users as u
|
||||
join project_users as pu on (pu.user_id = u.id)
|
||||
where pu.project_id = $2")
|
||||
|
||||
(declare retrieve-minimal-file)
|
||||
|
||||
(def sql:minimal-file
|
||||
(str "with files as (" sql:generic-project-files ")
|
||||
select id, project_id from files where id = $2"))
|
||||
(declare retrieve-file-users)
|
||||
|
||||
(s/def ::project-file-users
|
||||
(s/keys :req-un [::user ::file-id]))
|
||||
|
@ -134,20 +135,65 @@
|
|||
[{:keys [user file-id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(-> (retrieve-minimal-file conn user file-id)
|
||||
(p/then (fn [{:keys [id project-id]}]
|
||||
(db/query conn [sql:file-users id project-id]))))))
|
||||
(p/then #(retrieve-file-users conn %)))))
|
||||
|
||||
(def ^:private sql:minimal-file
|
||||
(str "with files as (" sql:generic-project-files ") "
|
||||
"select id, project_id from files where id = $2"))
|
||||
|
||||
(defn- retrieve-minimal-file
|
||||
[conn user-id file-id]
|
||||
(-> (db/query-one conn [sql:minimal-file user-id file-id])
|
||||
(p/then' su/raise-not-found-if-nil)))
|
||||
|
||||
(def ^:private sql:file-users
|
||||
"select u.id, u.fullname, u.photo
|
||||
from users as u
|
||||
join project_file_users as pfu on (pfu.user_id = u.id)
|
||||
where pfu.file_id = $1
|
||||
union all
|
||||
select u.id, u.fullname, u.photo
|
||||
from users as u
|
||||
join project_users as pu on (pu.user_id = u.id)
|
||||
where pu.project_id = $2")
|
||||
|
||||
(defn- retrieve-file-users
|
||||
[conn {:keys [id project-id] :as file}]
|
||||
(let [sqlv [sql:file-users id project-id]]
|
||||
(db/query conn sqlv)))
|
||||
|
||||
|
||||
;; --- Query: Images of the File
|
||||
|
||||
(declare retrieve-file-images)
|
||||
|
||||
(s/def ::project-file-images
|
||||
(s/keys :req-un [::user ::file-id]))
|
||||
|
||||
(sq/defquery ::project-file-images
|
||||
[{:keys [user file-id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(-> (retrieve-minimal-file conn user file-id)
|
||||
(p/then #(retrieve-file-images conn %)))))
|
||||
|
||||
(def ^:private sql:file-images
|
||||
"select pfi.*
|
||||
from project_file_images as pfi
|
||||
where pfi.file_id = $1")
|
||||
|
||||
(defn retrieve-file-images
|
||||
[conn {:keys [id] :as file}]
|
||||
(let [sqlv [sql:file-images id]
|
||||
xf (comp (map #(images/resolve-urls % :path :uri))
|
||||
(map #(images/resolve-urls % :thumb-path :thumb-uri)))]
|
||||
(-> (db/query conn sqlv)
|
||||
(p/then' #(into [] xf %)))))
|
||||
|
||||
;; --- Helpers
|
||||
|
||||
(defn decode-row
|
||||
[{:keys [metadata pages data] :as row}]
|
||||
[{:keys [pages data] :as row}]
|
||||
(when row
|
||||
(cond-> row
|
||||
data (assoc :data (blob/decode data))
|
||||
pages (assoc :pages (vec (remove nil? pages)))
|
||||
metadata (assoc :metadata (blob/decode metadata)))))
|
||||
pages (assoc :pages (vec (remove nil? pages))))))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue