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
use crate::prelude::*;

#[derive(Clone, PartialEq, Deserialize, Serialize)]
pub struct StudyRegistryRegistrar {
    pub id: Uuid,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
    pub deleted_at: Option<DateTime<Utc>>,
    pub name: String,
    pub secret_key: String,
}

pub async fn insert(
    conn: &mut PgConnection,
    pkey_policy: PKeyPolicy<Uuid>,
    name: &str,
    secret_key: &str,
) -> ModelResult<Uuid> {
    let res = sqlx::query!(
        "
INSERT INTO study_registry_registrars (id, name, secret_key)
VALUES ($1, $2, $3)
RETURNING id
    ",
        pkey_policy.into_uuid(),
        name,
        secret_key
    )
    .fetch_one(conn)
    .await?;
    Ok(res.id)
}

pub async fn get_by_id(conn: &mut PgConnection, id: Uuid) -> ModelResult<StudyRegistryRegistrar> {
    let res = sqlx::query_as!(
        StudyRegistryRegistrar,
        "
SELECT *
FROM study_registry_registrars
WHERE id = $1
  AND deleted_at IS NULL
        ",
        id,
    )
    .fetch_one(conn)
    .await?;
    Ok(res)
}

pub async fn get_by_secret_key(
    conn: &mut PgConnection,
    secret_key: &str,
) -> ModelResult<StudyRegistryRegistrar> {
    let res = sqlx::query_as!(
        StudyRegistryRegistrar,
        "
SELECT *
FROM study_registry_registrars
WHERE secret_key = $1
  AND deleted_at IS NULL
    ",
        secret_key
    )
    .fetch_one(conn)
    .await?;
    Ok(res)
}

pub async fn delete(conn: &mut PgConnection, id: Uuid) -> ModelResult<()> {
    sqlx::query!(
        "
UPDATE study_registry_registrars
SET deleted_at = now()
WHERE id = $1
        ",
        id,
    )
    .execute(conn)
    .await?;
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::test_helper::*;

    #[tokio::test]
    async fn secret_key_needs_to_be_long_enough() {
        insert_data!(:tx);
        let id_1 = Uuid::parse_str("88eff75b-4c8f-46f7-a857-9d804b5ec054").unwrap();
        let res = insert(
            tx.as_mut(),
            PKeyPolicy::Fixed(id_1),
            "test registrar",
            "12345",
        )
        .await;
        assert!(res.is_err(), "Expected too short key to produce error.");
    }

    #[tokio::test]
    async fn secret_key_needs_to_be_unique() {
        insert_data!(:tx);
        let id_1 = Uuid::parse_str("88eff75b-4c8f-46f7-a857-9d804b5ec054").unwrap();
        let res = insert(
            tx.as_mut(),
            PKeyPolicy::Fixed(id_1),
            "test registrar",
            "123456789-123456",
        )
        .await;
        assert!(res.is_ok(), "Expected insertion to succeed.");

        let id_2 = Uuid::parse_str("d06abb84-0cad-4372-ad2a-7f87d3c1e420").unwrap();
        let res = insert(
            tx.as_mut(),
            PKeyPolicy::Fixed(id_2),
            "test registrar 2",
            "123456789-123456",
        )
        .await;
        assert!(
            res.is_err(),
            "Expected insertion to fail with duplicate secret key."
        );
    }
}