shared/domain/
audio.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
//! Types for audio files.

use super::meta::AudioStyleId;
use crate::api::endpoints::PathPart;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
#[cfg(feature = "backend")]
use sqlx::postgres::PgRow;

/// Types for user audio library.
pub mod user {
    use macros::make_path_parts;
    use serde::{Deserialize, Serialize};

    use super::AudioId;
    use crate::api::endpoints::PathPart;

    make_path_parts!(UserAudioListPath => "/v1/user/me/audio");

    /// Response for listing.
    #[derive(Serialize, Deserialize, Debug)]
    pub struct UserAudioListResponse {
        /// the audio files returned.
        pub audio_files: Vec<UserAudioResponse>,
    }

    make_path_parts!(UserAudioGetPath => "/v1/user/me/audio/{}" => AudioId);

    /// Response for getting a single audio file.
    #[derive(Serialize, Deserialize, Debug)]
    pub struct UserAudioResponse {
        /// The audio file's metadata.
        pub metadata: UserAudio,
    }

    make_path_parts!(UserAudioCreatePath => "/v1/user/me/audio");

    /// Over the wire representation of an audio file's metadata.
    #[derive(Serialize, Deserialize, Debug)]
    pub struct UserAudio {
        /// The audio file's ID.
        pub id: AudioId,
        // more fields to be added
    }

    make_path_parts!(UserAudioUploadPath => "/v1/user/me/audio/{}/raw" => AudioId);

    /// Request indicating the size of an image for upload.
    #[derive(Serialize, Deserialize, Debug)]
    pub struct UserAudioUploadRequest {
        /// The size of the audio to be uploaded in bytes. Allows the API server to check that the file size is
        /// within limits and as a verification at GCS that the entire file was uploaded
        pub file_size: usize,
    }

    /// URL to upload an audio. Supports resumable uploading.
    #[derive(Serialize, Deserialize, Debug)]
    pub struct UserAudioUploadResponse {
        /// The session URI used for uploading, including the query for uploader ID
        pub session_uri: String,
    }

    make_path_parts!(UserAudioDeletePath => "/v1/user/me/audio/{}" => AudioId);
}

wrap_uuid! {
    /// Wrapper type around [`Uuid`](Uuid), represents the ID of an audio file.
    pub struct AudioId
}

/// Represents different kinds of audio.
#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
#[cfg_attr(feature = "backend", derive(sqlx::Type))]
#[repr(i16)]
pub enum AudioKind {
    /// Audio is an Mp3
    Mp3 = 0,
}

/// Response for getting a single audio file.
#[derive(Serialize, Deserialize, Debug)]
pub struct AudioResponse {
    /// The audio's metadata.
    pub metadata: AudioMetadata,
}

/// Over the wire representation of an audio file's metadata.
#[derive(Serialize, Deserialize, Debug)]
pub struct AudioMetadata {
    /// The audio's ID.
    pub id: AudioId,

    /// The name of the audio.
    pub name: String,

    /// The description of the audio file.
    pub description: String,

    /// Is the audio premium?
    pub is_premium: bool,

    /// When the audio should be considered published (if at all).
    pub publish_at: Option<DateTime<Utc>>,

    /// The styles associated with the audio file.
    pub styles: Vec<AudioStyleId>,

    /// What kind of audio this is.
    pub kind: AudioKind,

    /// Should the audio loop?
    pub is_looping: bool,

    /// When the audio was originally created.
    pub created_at: DateTime<Utc>,

    /// When the audio was last updated.
    pub updated_at: Option<DateTime<Utc>>,
}

// HACK: can't get `Vec<_>` directly from the DB. See `[crate::domain::image::ImageMetadata]`
#[cfg(feature = "backend")]
impl<'r> sqlx::FromRow<'r, PgRow> for AudioMetadata {
    fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
        let DbAudio {
            id,
            kind,
            name,
            description,
            is_premium,
            publish_at,
            styles,
            is_looping,
            created_at,
            updated_at,
        } = DbAudio::from_row(row)?;

        Ok(Self {
            id,
            kind,
            name,
            description,
            is_premium,
            publish_at,
            styles: styles.into_iter().map(|(it,)| it).collect(),
            is_looping,
            created_at,
            updated_at,
        })
    }
}

#[cfg_attr(feature = "backend", derive(sqlx::FromRow))]
#[cfg(feature = "backend")]
struct DbAudio {
    pub id: AudioId,
    pub kind: AudioKind,
    pub name: String,
    pub description: String,
    pub is_premium: bool,
    pub publish_at: Option<DateTime<Utc>>,
    pub styles: Vec<(AudioStyleId,)>,
    pub is_looping: bool,
    pub created_at: DateTime<Utc>,
    pub updated_at: Option<DateTime<Utc>>,
}