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:
|
server-dev:
|
||||||
cd server && make dev
|
cd server && make dev
|
||||||
|
|
||||||
|
server-test:
|
||||||
|
cd server && make test
|
||||||
|
|
||||||
client-dev:
|
client-dev:
|
||||||
cd v-client && make dev
|
cd v-client && make dev
|
||||||
|
|
||||||
|
|
|
@ -705,6 +705,7 @@ dependencies = [
|
||||||
"rand",
|
"rand",
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
"sha2",
|
"sha2",
|
||||||
|
"tempfile",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"uuid",
|
"uuid",
|
||||||
|
|
|
@ -15,3 +15,5 @@ tokio = { version = "1", features = ["full"] }
|
||||||
uuid = { version = "0.8", features = ["v4"] }
|
uuid = { version = "0.8", features = ["v4"] }
|
||||||
warp = { version = "0.3" }
|
warp = { version = "0.3" }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tempfile = { version = "3" }
|
||||||
|
|
|
@ -3,3 +3,9 @@
|
||||||
|
|
||||||
dev:
|
dev:
|
||||||
cargo watch -x run
|
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 std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||||
use warp::Filter;
|
use warp::Filter;
|
||||||
|
|
||||||
|
mod database;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
pub async fn main() {
|
pub async fn main() {
|
||||||
let echo_unauthenticated = warp::path!("api" / "v1" / "echo" / String).map(|param: String| {
|
let echo_unauthenticated = warp::path!("api" / "v1" / "echo" / String).map(|param: String| {
|
||||||
|
|
Loading…
Reference in New Issue