use crate::db_sqlite::SqliteConnection;
use crate::types::{Error, ErrorKind};
use crate::asn::AsnAssignmentStore;
use r2d2_sqlite::rusqlite;
#[derive(Debug, Clone)]
pub struct SqliteAsnAssignmentStore {
db: SqliteConnection,
}
impl SqliteAsnAssignmentStore {
pub fn new(db: SqliteConnection) -> Self {
SqliteAsnAssignmentStore { db }
}
}
impl AsnAssignmentStore for SqliteAsnAssignmentStore {
fn get_space(&self, space_id: i32) -> Result<crate::asn::AssignmentSpaceAsn, Error> {
let conn = self.db.get_conn()?;
let mut stmt = conn.prepare("SELECT id, name, description, space_visibility, asn_from, asn_to FROM assignment_space_asn WHERE id = ?")?;
let mut rows = stmt.query(rusqlite::params![space_id])?;
let row = rows.next()?;
let space = match row {
Some(row) => {
let space = crate::asn::AssignmentSpaceAsn {
id: row.get(0)?,
name: row.get(1)?,
description: row.get(2)?,
space_visibility: row.get(3)?,
asn_from: row.get(4)?,
asn_to: row.get(5)?,
};
Some(space)
},
None => None,
};
let space = if let Some(space) = space {
space
} else {
return Err(Error::new(ErrorKind::NotFound,"Assignment space not found".to_string()));
};
Ok(space)
}
fn get_spaces(&self) -> Result<Vec<crate::asn::AssignmentSpaceAsn>, Error> {
let conn = self.db.get_conn()?;
let mut stmt = conn.prepare("SELECT id, name, description, space_visibility, asn_from, asn_to FROM assignment_space_asn ORDER BY asn_from ASC")?;
let rows = stmt.query_map(rusqlite::params![], |row| {
Ok(crate::asn::AssignmentSpaceAsn {
id: row.get(0)?,
name: row.get(1)?,
description: row.get(2)?,
space_visibility: row.get(3)?,
asn_from: row.get(4)?,
asn_to: row.get(5)?,
})
})?;
let mut spaces = Vec::new();
for space in rows {
spaces.push(space?);
}
Ok(spaces)
}
fn create_space(&self, space: &crate::asn::AssignmentSpaceAsn) -> Result<i32, Error> {
let conn = self.db.get_conn()?;
let mut stmt = conn.prepare("INSERT INTO assignment_space_asn (name, description, space_visibility, asn_from, asn_to) VALUES (?, ?, ?, ?, ?)")?;
stmt.execute(rusqlite::params![space.name, space.description, space.space_visibility as i32, space.asn_from, space.asn_to])?;
Ok(conn.last_insert_rowid() as i32)
}
fn update_space(&self, id: i32, name: &str, description: &str) -> Result<(), Error> {
let conn = self.db.get_conn()?;
let mut stmt = conn.prepare("UPDATE assignment_space_asn SET name = ?, description = ? WHERE id = ?")?;
stmt.execute(rusqlite::params![name, description, id])?;
Ok(())
}
fn delete_space(&self, space_id: i32) -> Result<(), Error> {
let conn = self.db.get_conn()?;
let mut stmt = conn.prepare("DELETE FROM assignment_space_asn WHERE id = ?")?;
stmt.execute(rusqlite::params![space_id])?;
Ok(())
}
fn get_pool(&self, pool_id: i32) -> Result<crate::asn::AssignmentPoolAsn, Error> {
let conn = self.db.get_conn()?;
let mut stmt = conn.prepare("SELECT id, name, description, pool_visibility, assignment_space_id, asn_from, asn_to FROM assignment_pool_asn WHERE id = ?")?;
let mut rows = stmt.query(rusqlite::params![pool_id])?;
let row = rows.next()?;
let pool = match row {
Some(row) => {
let pool = crate::asn::AssignmentPoolAsn {
id: row.get(0)?,
name: row.get(1)?,
description: row.get(2)?,
pool_visibility: row.get(3)?,
assignment_space_id: row.get(4)?,
asn_from: row.get(5)?,
asn_to: row.get(6)?,
};
Some(pool)
},
None => None,
};
let pool = if let Some(pool) = pool {
pool
} else {
return Err(Error::new(ErrorKind::NotFound,"Assignment pool not found".to_string()));
};
Ok(pool)
}
fn get_pools(&self, space_id: i32) -> Result<Vec<crate::asn::AssignmentPoolAsn>, Error> {
let conn = self.db.get_conn()?;
let mut stmt = conn.prepare("SELECT id, name, description, pool_visibility, assignment_space_id, asn_from, asn_to FROM assignment_pool_asn WHERE assignment_space_id = ? ORDER BY asn_from ASC")?;
let rows = stmt.query_map(rusqlite::params![space_id], |row| {
Ok(crate::asn::AssignmentPoolAsn {
id: row.get(0)?,
name: row.get(1)?,
description: row.get(2)?,
pool_visibility: row.get(3)?,
assignment_space_id: row.get(4)?,
asn_from: row.get(5)?,
asn_to: row.get(6)?,
})
})?;
let mut pools = Vec::new();
for pool in rows {
pools.push(pool?);
}
Ok(pools)
}
fn create_pool(&self, pool: &crate::asn::AssignmentPoolAsn) -> Result<i32, Error> {
let mut conn = self.db.get_conn()?;
let tx = conn.transaction()?;
{
let mut space_stmt = tx.prepare("SELECT asn_from, asn_to FROM assignment_space_asn WHERE id = ?")?;
let space = space_stmt.query_row(rusqlite::params![pool.assignment_space_id], |row| {
Ok((row.get::<_, u32>(0)?, row.get::<_, u32>(1)?))
})?;
if pool.asn_from < space.0 || pool.asn_to > space.1 {
return Err(Error::new(ErrorKind::InvalidInput, "Pool ASN range is out of space range".to_string()));
}
}
{
let mut check_stmt = tx.prepare("SELECT COUNT(*) FROM assignment_pool_asn WHERE assignment_space_id = ? AND ((asn_from <= ? AND asn_to >= ?) OR (asn_from <= ? AND asn_to >= ?))")?;
let count: i32 = check_stmt.query_row(rusqlite::params![pool.assignment_space_id, pool.asn_from, pool.asn_from, pool.asn_to, pool.asn_to], |row| row.get(0))?;
if count > 0 {
return Err(Error::new(ErrorKind::InvalidInput, "Overlapping assignment pool exists".to_string()));
}
}
{
let mut insert_stmt = tx.prepare("INSERT INTO assignment_pool_asn (name, description, pool_visibility, assignment_space_id, asn_from, asn_to) VALUES (?, ?, ?, ?, ?, ?)")?;
insert_stmt.execute(rusqlite::params![pool.name, pool.description, pool.pool_visibility as i32, pool.assignment_space_id, pool.asn_from, pool.asn_to])?;
}
tx.commit()?;
let id = conn.last_insert_rowid() as i32;
Ok(id)
}
fn update_pool(&self, id: i32, name: &str, description: &str) -> Result<(), Error> {
let conn = self.db.get_conn()?;
let mut stmt = conn.prepare("UPDATE assignment_pool_asn SET name = ?, description = ? WHERE id = ?")?;
stmt.execute(rusqlite::params![name, description, id])?;
Ok(())
}
fn delete_pool(&self, pool_id: i32) -> Result<(), Error> {
let conn = self.db.get_conn()?;
let mut stmt = conn.prepare("DELETE FROM assignment_pool_asn WHERE id = ?")?;
stmt.execute(rusqlite::params![pool_id])?;
Ok(())
}
fn get_assignment(&self, assignment_id: i32) -> Result<crate::asn::AssignmentAsn, Error> {
let conn = self.db.get_conn()?;
let mut stmt = conn.prepare("SELECT id, name, description, assignment_pool_id, asn, assignment_visibility FROM assignment_asn WHERE id = ?")?;
let mut rows = stmt.query(rusqlite::params![assignment_id])?;
let row = rows.next()?;
let assignment = match row {
Some(row) => {
let assignment = crate::asn::AssignmentAsn {
id: row.get(0)?,
name: row.get(1)?,
description: row.get(2)?,
assignment_pool_id: row.get(3)?,
asn: row.get(4)?,
assignment_visibility: row.get(5)?,
};
Some(assignment)
},
None => None,
};
let assignment = if let Some(assignment) = assignment {
assignment
} else {
return Err(Error::new(ErrorKind::NotFound,"Assignment not found".to_string()));
};
Ok(assignment)
}
fn get_assignments(&self, pool_id: i32) -> Result<Vec<crate::asn::AssignmentAsn>, Error> {
let conn = self.db.get_conn()?;
let mut stmt = conn.prepare("SELECT id, name, description, assignment_pool_id, asn, assignment_visibility FROM assignment_asn WHERE assignment_pool_id = ? ORDER BY asn ASC")?;
let rows = stmt.query_map(rusqlite::params![pool_id], |row| {
Ok(crate::asn::AssignmentAsn {
id: row.get(0)?,
name: row.get(1)?,
description: row.get(2)?,
assignment_pool_id: row.get(3)?,
asn: row.get(4)?,
assignment_visibility: row.get(5)?,
})
})?;
let mut assignments = Vec::new();
for assignment in rows {
assignments.push(assignment?);
}
Ok(assignments)
}
fn create_assignment(&self, assignment: &crate::asn::AssignmentAsn) -> Result<i32, Error> {
let mut conn = self.db.get_conn()?;
let tx = conn.transaction()?;
{
let mut check_stmt = tx.prepare("SELECT COUNT(*) FROM assignment_asn WHERE assignment_pool_id = ? AND asn = ?")?;
let count: i32 = check_stmt.query_row(rusqlite::params![assignment.assignment_pool_id, assignment.asn], |row| row.get(0))?;
if count > 0 {
return Err(Error::new(ErrorKind::InvalidInput, "Overlapping assignment exists".to_string()));
}
}
{
let mut pool_stmt = tx.prepare("SELECT asn_from, asn_to FROM assignment_pool_asn WHERE id = ?")?;
let pool = pool_stmt.query_row(rusqlite::params![assignment.assignment_pool_id], |row| {
Ok((row.get::<_, u32>(0)?, row.get::<_, u32>(1)?))
})?;
if assignment.asn < pool.0 || assignment.asn > pool.1 {
return Err(Error::new(ErrorKind::InvalidInput, "Assignment ASN is out of pool range".to_string()));
}
}
{
let mut insert_stmt = tx.prepare("INSERT INTO assignment_asn (name, description, assignment_pool_id, asn, assignment_visibility) VALUES (?, ?, ?, ?, ?)")?;
insert_stmt.execute(rusqlite::params![assignment.name, assignment.description, assignment.assignment_pool_id, assignment.asn, assignment.assignment_visibility])?;
}
tx.commit()?;
let id = conn.last_insert_rowid() as i32;
Ok(id)
}
fn update_assignment(&self, id: i32, name: &str, description: &str) -> Result<(), Error> {
let conn = self.db.get_conn()?;
let mut stmt = conn.prepare("UPDATE assignment_asn SET name = ?, description = ? WHERE id = ?")?;
stmt.execute(rusqlite::params![name, description, id])?;
Ok(())
}
fn delete_assignment(&self, assignment_id: i32) -> Result<(), Error> {
let conn = self.db.get_conn()?;
let mut stmt = conn.prepare("DELETE FROM assignment_asn WHERE id = ?")?;
stmt.execute(rusqlite::params![assignment_id])?;
Ok(())
}
}