matrix_sdk_indexeddb/media_store/
migrations.rs1use indexed_db_futures::{
16 database::Database,
17 error::{DomException, Error, OpenDbError},
18 transaction::Transaction,
19};
20use thiserror::Error;
21
22pub mod current {
24 use super::{Version, v2};
25
26 pub const VERSION: Version = Version::V2;
27 pub use v2::keys;
28}
29
30#[allow(unused)]
33pub async fn open_and_upgrade_db(name: &str) -> Result<Database, OpenDbError> {
34 Database::open(name)
35 .with_version(current::VERSION as u32)
36 .with_on_upgrade_needed(|event, transaction| {
37 let mut version = Version::try_from(event.old_version() as u32)?;
38 while version < current::VERSION {
39 version = match version.upgrade(transaction)? {
40 Some(next) => next,
41 None => current::VERSION, };
43 }
44 Ok(())
45 })
46 .await
47}
48
49#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
51#[repr(u32)]
52pub enum Version {
53 V0 = 0,
55 V1 = 1,
57 V2 = 2,
59}
60
61impl Version {
62 pub fn upgrade(self, transaction: &Transaction<'_>) -> Result<Option<Self>, Error> {
64 match self {
65 Self::V0 => v0::upgrade(transaction).map(Some),
66 Self::V1 => v1::upgrade(transaction).map(Some),
67 Self::V2 => Ok(None),
68 }
69 }
70}
71
72#[derive(Debug, Error)]
73#[error("unknown version: {0}")]
74pub struct UnknownVersionError(u32);
75
76impl TryFrom<u32> for Version {
77 type Error = UnknownVersionError;
78
79 fn try_from(value: u32) -> Result<Self, Self::Error> {
80 match value {
81 0 => Ok(Version::V0),
82 1 => Ok(Version::V1),
83 2 => Ok(Version::V2),
84 v => Err(UnknownVersionError(v)),
85 }
86 }
87}
88
89impl From<UnknownVersionError> for Error {
90 fn from(value: UnknownVersionError) -> Self {
91 let message = format!("unknown version: {}", value.0);
92 let name = "UnknownVersionError";
93 match web_sys::DomException::new_with_message_and_name(&message, name) {
94 Ok(inner) => Self::DomException(DomException::DataError(inner)),
95 Err(err) => err.into(),
96 }
97 }
98}
99
100pub mod v0 {
101 use super::*;
102
103 pub fn upgrade(transaction: &Transaction<'_>) -> Result<Version, Error> {
105 v1::create_object_stores(transaction.db())?;
106 Ok(Version::V1)
107 }
108}
109
110pub mod v1 {
111 use indexed_db_futures::Build;
112
113 use super::*;
114
115 pub mod keys {
116 pub const CORE: &str = "core";
117 pub const CORE_KEY_PATH: &str = "id";
118 pub const LEASES: &str = "leases";
119 pub const LEASES_KEY_PATH: &str = "id";
120 pub const MEDIA_RETENTION_POLICY_KEY: &str = "media_retention_policy";
121 pub const MEDIA_CLEANUP_TIME_KEY: &str = "media_cleanup_time";
122 pub const MEDIA_METADATA: &str = "media_metadata";
123 pub const MEDIA_METADATA_KEY_PATH: &str = "id";
124 pub const MEDIA_METADATA_URI: &str = "media_metadata_uri";
125 pub const MEDIA_METADATA_URI_KEY_PATH: &str = "uri";
126 pub const MEDIA_METADATA_CONTENT_SIZE: &str = "media_metadata_content_size";
127 pub const MEDIA_METADATA_CONTENT_SIZE_KEY_PATH: &str = "content_size";
128 pub const MEDIA_METADATA_LAST_ACCESS: &str = "media_metadata_last_access";
129 pub const MEDIA_METADATA_LAST_ACCESS_KEY_PATH: &str = "last_access";
130 pub const MEDIA_METADATA_RETENTION: &str = "media_metadata_retention";
131 pub const MEDIA_METADATA_RETENTION_KEY_PATH: &str = "retention";
132 pub const MEDIA_CONTENT: &str = "media_content";
133 pub const MEDIA_CONTENT_KEY_PATH: &str = "id";
134 }
135
136 pub fn create_object_stores(db: &Database) -> Result<(), Error> {
138 create_core_object_store(db)?;
139 create_lease_object_store(db)?;
140 create_media_metadata_object_store(db)?;
141 create_media_content_object_store(db)?;
142 Ok(())
143 }
144
145 fn create_core_object_store(db: &Database) -> Result<(), Error> {
149 let _ =
150 db.create_object_store(keys::CORE).with_key_path(keys::CORE_KEY_PATH.into()).build()?;
151 Ok(())
152 }
153
154 fn create_lease_object_store(db: &Database) -> Result<(), Error> {
156 let _ = db
157 .create_object_store(keys::LEASES)
158 .with_key_path(keys::LEASES_KEY_PATH.into())
159 .build()?;
160 Ok(())
161 }
162
163 fn create_media_metadata_object_store(db: &Database) -> Result<(), Error> {
178 let media = db
179 .create_object_store(keys::MEDIA_METADATA)
180 .with_key_path(keys::MEDIA_METADATA_KEY_PATH.into())
181 .build()?;
182 let _ = media
183 .create_index(keys::MEDIA_METADATA_URI, keys::MEDIA_METADATA_URI_KEY_PATH.into())
184 .build()?;
185 let _ = media
186 .create_index(
187 keys::MEDIA_METADATA_CONTENT_SIZE,
188 keys::MEDIA_METADATA_CONTENT_SIZE_KEY_PATH.into(),
189 )
190 .build()?;
191 let _ = media
192 .create_index(
193 keys::MEDIA_METADATA_LAST_ACCESS,
194 keys::MEDIA_METADATA_LAST_ACCESS_KEY_PATH.into(),
195 )
196 .build()?;
197 let _ = media
198 .create_index(
199 keys::MEDIA_METADATA_RETENTION,
200 keys::MEDIA_METADATA_RETENTION_KEY_PATH.into(),
201 )
202 .build()?;
203 Ok(())
204 }
205
206 fn create_media_content_object_store(db: &Database) -> Result<(), Error> {
210 let _ = db
211 .create_object_store(keys::MEDIA_CONTENT)
212 .with_key_path(keys::MEDIA_CONTENT_KEY_PATH.into())
213 .build()?;
214 Ok(())
215 }
216
217 pub fn upgrade(transaction: &Transaction<'_>) -> Result<Version, Error> {
219 v2::empty_leases(transaction)?;
220 Ok(Version::V2)
221 }
222}
223
224mod v2 {
225 pub use super::v1::keys;
227 use super::*;
228
229 pub fn empty_leases(transaction: &Transaction<'_>) -> Result<(), Error> {
232 let object_store = transaction.object_store(keys::LEASES)?;
233
234 object_store.clear()?;
236
237 Ok(())
238 }
239}