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
|
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
#[derive(Debug, Serialize, Deserialize, FromRow, Clone, PartialEq)]
pub struct Location {
pub id: i64,
pub latitude: f64,
pub longitude: f64,
pub user_id: i64,
}
pub struct LocationRepository<'a> {
pub db: &'a sqlx::SqlitePool,
}
impl<'a> LocationRepository<'a> {
pub async fn list_locations(&self) -> Result<Vec<Location>, sqlx::Error> {
sqlx::query_as::<_, Location>("SELECT id, latitude, longitude, user_id FROM locations")
.fetch_all(self.db)
.await
}
pub async fn get_location(&self, id: i64) -> Result<Option<Location>, sqlx::Error> {
sqlx::query_as::<_, Location>("SELECT id, latitude, longitude, user_id FROM locations WHERE id = ?")
.bind(id)
.fetch_optional(self.db)
.await
}
pub async fn create_location(&self, latitude: f64, longitude: f64, user_id: i64) -> Result<Location, sqlx::Error> {
sqlx::query_as::<_, Location>(
"INSERT INTO locations (latitude, longitude, user_id) VALUES (?, ?, ?) RETURNING id, latitude, longitude, user_id"
)
.bind(latitude)
.bind(longitude)
.bind(user_id)
.fetch_one(self.db)
.await
}
pub async fn update_location(&self, id: i64, latitude: f64, longitude: f64) -> Result<Location, sqlx::Error> {
sqlx::query_as::<_, Location>(
"UPDATE locations SET latitude = ?, longitude = ? WHERE id = ? RETURNING id, latitude, longitude, user_id"
)
.bind(latitude)
.bind(longitude)
.bind(id)
.fetch_one(self.db)
.await
}
pub async fn delete_location(&self, id: i64) -> Result<(), sqlx::Error> {
sqlx::query("DELETE FROM locations WHERE id = ?")
.bind(id)
.execute(self.db)
.await?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::users::{UserRepository, UserRole};
use sqlx::{SqlitePool, Executor};
use tokio;
async fn setup_db() -> SqlitePool {
let pool = SqlitePool::connect(":memory:").await.unwrap();
pool.execute(
"CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id TEXT NOT NULL UNIQUE,
role TEXT NOT NULL DEFAULT 'user'
);"
).await.unwrap();
pool.execute(
"CREATE TABLE locations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
latitude REAL NOT NULL,
longitude REAL NOT NULL,
user_id INTEGER NOT NULL,
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE NO ACTION
);"
).await.unwrap();
pool
}
async fn create_user(pool: &SqlitePool) -> i64 {
let repo = UserRepository { db: pool };
let user = repo.create_user(None, Some(UserRole::User)).await.unwrap();
user.id
}
#[tokio::test]
async fn test_create_and_get_location() {
let db = setup_db().await;
let user_id = create_user(&db).await;
let repo = LocationRepository { db: &db };
let loc = repo.create_location(60.0, 24.0, user_id).await.unwrap();
let fetched = repo.get_location(loc.id).await.unwrap().unwrap();
assert_eq!(fetched.latitude, 60.0);
assert_eq!(fetched.longitude, 24.0);
assert_eq!(fetched.user_id, user_id);
}
#[tokio::test]
async fn test_update_location() {
let db = setup_db().await;
let user_id = create_user(&db).await;
let repo = LocationRepository { db: &db };
let loc = repo.create_location(60.0, 24.0, user_id).await.unwrap();
let updated = repo.update_location(loc.id, 61.0, 25.0).await.unwrap();
assert_eq!(updated.latitude, 61.0);
assert_eq!(updated.longitude, 25.0);
}
#[tokio::test]
async fn test_delete_location() {
let db = setup_db().await;
let user_id = create_user(&db).await;
let repo = LocationRepository { db: &db };
let loc = repo.create_location(60.0, 24.0, user_id).await.unwrap();
repo.delete_location(loc.id).await.unwrap();
let fetched = repo.get_location(loc.id).await.unwrap();
assert!(fetched.is_none());
}
#[tokio::test]
async fn test_list_locations() {
let db = setup_db().await;
let user_id = create_user(&db).await;
let repo = LocationRepository { db: &db };
repo.create_location(60.0, 24.0, user_id).await.unwrap();
repo.create_location(61.0, 25.0, user_id).await.unwrap();
let locations = repo.list_locations().await.unwrap();
assert_eq!(locations.len(), 2);
}
}
|