Set up the database table with users, invitations, and sessions
This commit is contained in:
parent
57b438c6e6
commit
6e1e4d7811
9
Makefile
9
Makefile
|
@ -1,9 +1,16 @@
|
|||
|
||||
.PHONY: server-dev client-dev client-test
|
||||
.PHONY: server-dev server-test client-dev client-test
|
||||
|
||||
test:
|
||||
cd server && make test-oneshot
|
||||
cd v-client && make test
|
||||
|
||||
server-dev:
|
||||
cd server && make dev
|
||||
|
||||
server-test:
|
||||
cd server && make test
|
||||
|
||||
client-dev:
|
||||
cd v-client && make dev
|
||||
|
||||
|
|
|
@ -705,6 +705,7 @@ dependencies = [
|
|||
"rand",
|
||||
"rusqlite",
|
||||
"sha2",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"uuid",
|
||||
|
|
|
@ -15,3 +15,5 @@ tokio = { version = "1", features = ["full"] }
|
|||
uuid = { version = "0.8", features = ["v4"] }
|
||||
warp = { version = "0.3" }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = { version = "3" }
|
||||
|
|
|
@ -3,3 +3,9 @@
|
|||
|
||||
dev:
|
||||
cargo watch -x run
|
||||
|
||||
test:
|
||||
cargo watch -x test
|
||||
|
||||
test-oneshot:
|
||||
cargo test
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
fn main() {
|
||||
println!("There is a tool");
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
use rusqlite::{params, Connection};
|
||||
use std::{
|
||||
ops::{Deref, DerefMut},
|
||||
path::PathBuf,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
pub struct ManagedConnection<'a> {
|
||||
pool: &'a Database,
|
||||
connection: Option<Connection>,
|
||||
}
|
||||
|
||||
pub struct Database {
|
||||
file_path: PathBuf,
|
||||
pool: Arc<Mutex<Vec<Connection>>>,
|
||||
}
|
||||
|
||||
impl Database {
|
||||
pub fn new(file_path: PathBuf) -> Result<Database, anyhow::Error> {
|
||||
let mut connection = Connection::open(file_path.clone())?;
|
||||
|
||||
let tx = connection.transaction()?;
|
||||
let version: i32 = tx.pragma_query_value(None, "user_version", |r| r.get(0))?;
|
||||
if version == 0 {
|
||||
tx.execute_batch(
|
||||
"CREATE TABLE users (id STRING PRIMARY KEY, name TEXT);
|
||||
CREATE TABLE invitations (token STRING PRIMARY KEY, user_id STRING, FOREIGN KEY(user_id) REFERENCES users(id));
|
||||
CREATE TABLE sessions (token STRING PRIMARY KEY, user_id STRING, FOREIGN KEY(user_id) REFERENCES users(id));
|
||||
PRAGMA user_version = 1;",
|
||||
)?;
|
||||
}
|
||||
tx.commit()?;
|
||||
|
||||
Ok(Database {
|
||||
file_path,
|
||||
pool: Arc::new(Mutex::new(vec![connection])),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn connect<'a>(&'a self) -> Result<ManagedConnection<'a>, anyhow::Error> {
|
||||
let mut pool = self.pool.lock().unwrap();
|
||||
match pool.pop() {
|
||||
Some(connection) => Ok(ManagedConnection {
|
||||
pool: &self,
|
||||
connection: Some(connection),
|
||||
}),
|
||||
None => {
|
||||
let connection = Connection::open(self.file_path.clone())?;
|
||||
Ok(ManagedConnection {
|
||||
pool: &self,
|
||||
connection: Some(connection),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn release(&self, connection: Connection) {
|
||||
let mut pool = self.pool.lock().unwrap();
|
||||
pool.push(connection);
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for ManagedConnection<'_> {
|
||||
type Target = Connection;
|
||||
|
||||
fn deref(&self) -> &Connection {
|
||||
self.connection.as_ref().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for ManagedConnection<'_> {
|
||||
fn deref_mut(&mut self) -> &mut Connection {
|
||||
self.connection.as_mut().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ManagedConnection<'_> {
|
||||
fn drop(&mut self) {
|
||||
self.pool.release(self.connection.take().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
#[test]
|
||||
fn it_can_create_users() {
|
||||
let path = NamedTempFile::new().unwrap().into_temp_path();
|
||||
let database = Database::new(path.to_path_buf()).unwrap();
|
||||
let mut connection = database.connect().unwrap();
|
||||
let tr = connection.transaction().unwrap();
|
||||
tr.execute(
|
||||
"INSERT INTO users VALUES(?, ?)",
|
||||
params!["abcdefg", "mercer"],
|
||||
)
|
||||
.unwrap();
|
||||
tr.commit().unwrap();
|
||||
|
||||
let connection = database.connect().unwrap();
|
||||
let id: Option<String> = connection
|
||||
.query_row(
|
||||
"SELECT id FROM users WHERE name = ?",
|
||||
[String::from("mercer")],
|
||||
|row| row.get("id"),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(id, Some(String::from("abcdefg")));
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
use warp::Filter;
|
||||
|
||||
mod database;
|
||||
|
||||
#[tokio::main]
|
||||
pub async fn main() {
|
||||
let echo_unauthenticated = warp::path!("api" / "v1" / "echo" / String).map(|param: String| {
|
||||
|
|
Loading…
Reference in New Issue