refactor(indexeddb): add indexed types and keys for media metadata

Signed-off-by: Michael Goldenberg <m@mgoldenberg.net>
This commit is contained in:
Michael Goldenberg
2025-10-17 09:59:51 -04:00
committed by Damir Jelić
parent 6036f19af6
commit 6ff186b744
@@ -48,7 +48,7 @@ use crate::{
},
foreign::{ignore_media_retention_policy, unix_time},
},
types::{Lease, Media, MediaCleanupTime, MediaContent, UnixTime},
types::{Lease, Media, MediaCleanupTime, MediaContent, MediaMetadata, UnixTime},
},
serializer::{
indexed_type::constants::{INDEXED_KEY_LOWER_U64, INDEXED_KEY_UPPER_U64},
@@ -74,10 +74,8 @@ pub type IndexedMediaRetentionPolicyContent = MaybeEncrypted;
/// cleaned - i.e., as a [`UnixTime`]
pub type IndexedMediaCleanupTimeContent = MaybeEncrypted;
/// A (possibly) encrypted representation of a [`MediaMetadata`][1]
///
/// [1]: crate::media_store::types::MediaMetadata
pub type IndexedMediaMetadata = MaybeEncrypted;
/// A (possibly) encrypted representation of a [`MediaMetadata`]
pub type IndexedMediaMetadataContent = MaybeEncrypted;
/// A representation of the size in bytes of the [`IndexedMediaContent`] which
/// is suitable for use in an IndexedDB key
@@ -579,6 +577,318 @@ impl<'a> IndexedPrefixKeyComponentBounds<'a, Media, IgnoreMediaRetentionPolicy>
}
}
/// Represents the [`MEDIA_METADATA`][1] object store.
///
/// [1]: crate::media_store::migrations::v1::create_media_metadata_object_store
#[derive(Debug, Serialize, Deserialize)]
pub struct IndexedMediaMetadata {
/// The primary key of the object store
pub id: IndexedMediaMetadataIdKey,
/// The (possibly) hashed [`MxcUri`] of the media derived from
/// [`MediaRequestParameters::uri`]
pub uri: IndexedMediaMetadataUriKey,
/// The size (in bytes) of the media content and whether to ignore the
/// [`MediaRetentionPolicy`]
pub content_size: IndexedMediaMetadataContentSizeKey,
/// The last time the media was accessed and whether to ignore the
/// [`MediaRetentionPolicy`]
pub last_access: IndexedMediaMetadataLastAccessKey,
/// The last the media was accessed, the size (in bytes) of the media
/// content, and whether to ignore the [`MediaRetentionPolicy`]
pub retention: IndexedMediaMetadataRetentionKey,
/// The (possibly) encrypted content - i.e., [`MediaMetadata`]
pub content: IndexedMediaMetadataContent,
}
impl Indexed for MediaMetadata {
const OBJECT_STORE: &'static str = keys::MEDIA_METADATA;
type IndexedType = IndexedMediaMetadata;
type Error = IndexedMediaError;
fn to_indexed(
&self,
serializer: &SafeEncodeSerializer,
) -> Result<Self::IndexedType, Self::Error> {
Ok(Self::IndexedType {
id: <IndexedMediaMetadataIdKey as IndexedKey<Self>>::encode(
&self.request_parameters,
serializer,
),
uri: <IndexedMediaMetadataUriKey as IndexedKey<Self>>::encode(
self.request_parameters.uri(),
serializer,
),
content_size: IndexedMediaMetadataContentSizeKey::encode(
(self.ignore_policy, self.content_size),
serializer,
),
last_access: IndexedMediaMetadataLastAccessKey::encode(
(self.ignore_policy, self.last_access),
serializer,
),
retention: IndexedMediaMetadataRetentionKey::encode(
(self.ignore_policy, self.last_access, self.content_size),
serializer,
),
content: serializer.maybe_encrypt_value(self)?,
})
}
fn from_indexed(
indexed: Self::IndexedType,
serializer: &SafeEncodeSerializer,
) -> Result<Self, Self::Error> {
Ok(serializer.maybe_decrypt_value(indexed.content)?)
}
}
/// The primary key of the [`MEDIA_METADATA`][1] object store, which is
/// constructed from:
///
/// - The (possibly) hashed value returned by
/// [`MediaRequestParameters::unique_key`]
///
/// [1]: crate::media_store::migrations::v1::create_media_metadata_object_store
#[derive(Debug, Serialize, Deserialize)]
pub struct IndexedMediaMetadataIdKey(String);
impl IndexedKey<MediaMetadata> for IndexedMediaMetadataIdKey {
type KeyComponents<'a> = &'a MediaRequestParameters;
fn encode(components: Self::KeyComponents<'_>, serializer: &SafeEncodeSerializer) -> Self {
Self(serializer.encode_key_as_string(keys::MEDIA_METADATA, components.unique_key()))
}
}
/// The value associated with the [`ur`](IndexedMediaMetadata::uri) index of the
/// [`MEDIA_METADATA`][1] object store, which is constructed from:
///
/// - The (possibly) hashed [`MxcUri`] returned by
/// [`MediaRequestParameters::uri`]
///
/// [1]: crate::media_store::migrations::v1::create_media_metadata_object_store
#[derive(Debug, Serialize, Deserialize)]
pub struct IndexedMediaMetadataUriKey(String);
impl IndexedKey<MediaMetadata> for IndexedMediaMetadataUriKey {
const INDEX: Option<&'static str> = Some(keys::MEDIA_METADATA_URI);
type KeyComponents<'a> = &'a MxcUri;
fn encode(components: Self::KeyComponents<'_>, serializer: &SafeEncodeSerializer) -> Self {
Self(serializer.encode_key_as_string(keys::MEDIA_METADATA_URI, components))
}
}
/// The value associated with the
/// [`content_size`](IndexedMediaMetadata::content_size) index of the
/// [`MEDIA_METADATA`][1] object store, which is constructed from:
///
/// - The value of [`IgnoreMediaRetentionPolicy`]
/// - The size in bytes of the associated [`IndexedMediaMetadata::content`]
///
/// [1]: crate::media_store::migrations::v1::create_media_metadata_object_store
#[derive(Debug, Serialize, Deserialize)]
pub struct IndexedMediaMetadataContentSizeKey(
#[serde(with = "ignore_media_retention_policy")] IgnoreMediaRetentionPolicy,
IndexedMediaContentSize,
);
impl IndexedMediaMetadataContentSizeKey {
/// Returns the [`IgnoreMediaRetentionPolicy`] value of the associated
/// [`IndexedMediaMetadata`]
pub fn ignore_policy(&self) -> IgnoreMediaRetentionPolicy {
self.0
}
/// Returns the size in bytes of the associated [`IndexedMediaContent`]
pub fn content_size(&self) -> usize {
self.1
}
}
impl IndexedKey<MediaMetadata> for IndexedMediaMetadataContentSizeKey {
const INDEX: Option<&'static str> = Some(keys::MEDIA_METADATA_CONTENT_SIZE);
type KeyComponents<'a> = (IgnoreMediaRetentionPolicy, IndexedMediaContentSize);
fn encode(
(ignore_policy, content_size): Self::KeyComponents<'_>,
_: &SafeEncodeSerializer,
) -> Self {
Self(ignore_policy, content_size)
}
}
impl IndexedKeyComponentBounds<MediaMetadata> for IndexedMediaMetadataContentSizeKey {
fn lower_key_components() -> Self::KeyComponents<'static> {
Self::lower_key_components_with_prefix(IgnoreMediaRetentionPolicy::No)
}
fn upper_key_components() -> Self::KeyComponents<'static> {
Self::lower_key_components_with_prefix(IgnoreMediaRetentionPolicy::Yes)
}
}
impl<'a> IndexedPrefixKeyComponentBounds<'a, MediaMetadata, IgnoreMediaRetentionPolicy>
for IndexedMediaMetadataContentSizeKey
{
fn lower_key_components_with_prefix(
prefix: IgnoreMediaRetentionPolicy,
) -> Self::KeyComponents<'a> {
(prefix, INDEXED_KEY_LOWER_MEDIA_CONTENT_SIZE)
}
fn upper_key_components_with_prefix(
prefix: IgnoreMediaRetentionPolicy,
) -> Self::KeyComponents<'a> {
(prefix, INDEXED_KEY_UPPER_MEDIA_CONTENT_SIZE)
}
}
/// The value associated with the
/// [`last_access`](IndexedMediaMetadata::last_access) index of the
/// [`MEDIA_METADATA`][1] object store, which is constructed from:
///
/// - The value of [`IgnoreMediaRetentionPolicy`]
/// - The last time the associated [`IndexedMediaContent`] was accessed,
/// represented as a [`UnixTime`]
///
/// [1]: crate::media_store::migrations::v1::create_media_metadata_object_store
#[derive(Debug, Serialize, Deserialize)]
pub struct IndexedMediaMetadataLastAccessKey(
#[serde(with = "ignore_media_retention_policy")] IgnoreMediaRetentionPolicy,
#[serde(with = "unix_time")] UnixTime,
);
impl IndexedMediaMetadataLastAccessKey {
/// Returns the [`IgnoreMediaRetentionPolicy`] value of the associated
/// [`IndexedMedia`]
pub fn ignore_policy(&self) -> IgnoreMediaRetentionPolicy {
self.0
}
/// Returns the last time the associated [`IndexedMediaContent`] was
/// accessed as a [`UnixTime`]
pub fn last_access(&self) -> UnixTime {
self.1
}
}
impl IndexedKey<MediaMetadata> for IndexedMediaMetadataLastAccessKey {
const INDEX: Option<&'static str> = Some(keys::MEDIA_METADATA_LAST_ACCESS);
type KeyComponents<'a> = (IgnoreMediaRetentionPolicy, UnixTime);
fn encode(
(ignore_policy, last_access): Self::KeyComponents<'_>,
_: &SafeEncodeSerializer,
) -> Self {
Self(ignore_policy, last_access)
}
}
impl IndexedKeyComponentBounds<MediaMetadata> for IndexedMediaMetadataLastAccessKey {
fn lower_key_components() -> Self::KeyComponents<'static> {
Self::lower_key_components_with_prefix(IgnoreMediaRetentionPolicy::No)
}
fn upper_key_components() -> Self::KeyComponents<'static> {
Self::lower_key_components_with_prefix(IgnoreMediaRetentionPolicy::Yes)
}
}
impl<'a> IndexedPrefixKeyComponentBounds<'a, MediaMetadata, IgnoreMediaRetentionPolicy>
for IndexedMediaMetadataLastAccessKey
{
fn lower_key_components_with_prefix(
prefix: IgnoreMediaRetentionPolicy,
) -> Self::KeyComponents<'a> {
(prefix, INDEXED_KEY_LOWER_UNIX_TIME)
}
fn upper_key_components_with_prefix(
prefix: IgnoreMediaRetentionPolicy,
) -> Self::KeyComponents<'a> {
(prefix, INDEXED_KEY_UPPER_UNIX_TIME)
}
}
/// The value associated with the [`retention`](IndexedMediaMetadata::retention)
/// index of the [`MEDIA_METADATA`][1] object store, which is constructed from:
///
/// - The value of [`IgnoreMediaRetentionPolicy`]
/// - The last time the associated [`IndexedMediaContent`] was accessed,
/// represented as a [`UnixTime`]
/// - The size in bytes of the associated [`IndexedMediaContent`]
///
/// [1]: crate::media_store::migrations::v1::create_media_metadata_object_store
#[derive(Debug, Serialize, Deserialize)]
pub struct IndexedMediaMetadataRetentionKey(
#[serde(with = "ignore_media_retention_policy")] IgnoreMediaRetentionPolicy,
#[serde(with = "unix_time")] UnixTime,
IndexedMediaContentSize,
);
impl IndexedMediaMetadataRetentionKey {
/// Returns the [`IgnoreMediaRetentionPolicy`] value of the associated
/// [`IndexedMedia`]
pub fn ignore_policy(&self) -> IgnoreMediaRetentionPolicy {
self.0
}
/// Returns the last time the associated [`IndexedMediaContent`] was
/// accessed as a [`UnixTime`]
pub fn last_access(&self) -> UnixTime {
self.1
}
/// Returns the size in bytes of the associated [`IndexedMediaContent`]
pub fn content_size(&self) -> usize {
self.2
}
}
impl IndexedKey<MediaMetadata> for IndexedMediaMetadataRetentionKey {
const INDEX: Option<&'static str> = Some(keys::MEDIA_METADATA_RETENTION);
type KeyComponents<'a> = (IgnoreMediaRetentionPolicy, UnixTime, IndexedMediaContentSize);
fn encode(
(ignore_policy, last_access, content_size): Self::KeyComponents<'_>,
_: &SafeEncodeSerializer,
) -> Self {
Self(ignore_policy, last_access, content_size)
}
}
impl IndexedKeyComponentBounds<MediaMetadata> for IndexedMediaMetadataRetentionKey {
fn lower_key_components() -> Self::KeyComponents<'static> {
Self::lower_key_components_with_prefix(IgnoreMediaRetentionPolicy::No)
}
fn upper_key_components() -> Self::KeyComponents<'static> {
Self::lower_key_components_with_prefix(IgnoreMediaRetentionPolicy::Yes)
}
}
impl<'a> IndexedPrefixKeyComponentBounds<'a, MediaMetadata, IgnoreMediaRetentionPolicy>
for IndexedMediaMetadataRetentionKey
{
fn lower_key_components_with_prefix(
prefix: IgnoreMediaRetentionPolicy,
) -> Self::KeyComponents<'a> {
(prefix, INDEXED_KEY_LOWER_UNIX_TIME, INDEXED_KEY_LOWER_MEDIA_CONTENT_SIZE)
}
fn upper_key_components_with_prefix(
prefix: IgnoreMediaRetentionPolicy,
) -> Self::KeyComponents<'a> {
(prefix, INDEXED_KEY_UPPER_UNIX_TIME, INDEXED_KEY_UPPER_MEDIA_CONTENT_SIZE)
}
}
/// Represents the [`MEDIA_CONTENT`][1] object store.
///
/// [1]: crate::media_store::migrations::v1::create_media_content_object_store