Skip to content
This repository has been archived by the owner on Jun 6, 2024. It is now read-only.

Aditya/base routes #5

Merged
merged 12 commits into from
Mar 14, 2024
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
PORT=3000
7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
axum = {version = "0.7.4"}
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.0", features = ["full"] }
serde_json = "1.0"
tower-http = { version = "0.4.0", features = ["full"] }
dotenv = "0.15.0"
rocksdb = "0.22.0"

pretty_assertions = "0.7"
select = "0.5"
1 change: 1 addition & 0 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod parameters;
13 changes: 13 additions & 0 deletions src/config/parameters.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use dotenv;

// load the env file
pub fn init() {
dotenv::dotenv().ok().expect("Failed to load .env file");
}

// get the parameters from the env file and throw errors appropriately
pub fn get(parameter: &str) -> String {
let env_parameter = std::env::var(parameter)
.expect(&format!("{} is not defined in the environment", parameter));
env_parameter
}
2 changes: 2 additions & 0 deletions src/handlers/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod namespace_handler;
pub mod table_handler;
74 changes: 74 additions & 0 deletions src/handlers/namespace_handler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use axum::{
extract::{Json, Path},
http::StatusCode,
response::IntoResponse,
};



#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct Namespace {

}


pub async fn list_namespaces() -> Json<Vec<String>> {
// Logic to list namespaces
let namespaces: Vec<String> = vec!["accounting".to_string(), "tax".to_string(), "paid".to_string()];
Json(namespaces)
}

pub async fn create_namespace(new_namespace: Json<Namespace>) -> Json<Namespace> {
// Logic to create a new namespace

// Logic to persist the namespace and add properties
new_namespace
}

#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct NamespaceMetadata {
// Define your namespace metadata properties here
// Example: pub metadata_property: String,
data: String,
}

#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct NamespaceProperties {
data: String,
}

pub async fn load_namespace_metadata(Path(namespace): Path<String>) -> Json<NamespaceMetadata> {
print!("Namespaces: {}", namespace);
// Logic to load metadata properties for a namespace
let metadata = NamespaceMetadata {
data: namespace,
// Populate with actual metadata properties
};
Json(metadata)
}

pub async fn namespace_exists(Path(namespace): Path<String>) -> impl IntoResponse {
// Logic to check if a namespace exists
// This route just needs to return a status code, no body required
// Return HTTP status code 200 to indicate namespace exists
StatusCode::FOUND
}

pub async fn drop_namespace(Path(namespace): Path<String>) -> impl IntoResponse {
// Logic to drop a namespace from the catalog
// Ensure the namespace is empty before dropping
// Return HTTP status code 204 to indicate successful deletion
StatusCode::NO_CONTENT
}

pub async fn set_namespace_properties(Path(namespace): Path<String>) -> Json<NamespaceProperties> {
// Logic to set and/or remove properties on a namespace
// Deserialize request body and process properties
// Return HTTP status code 200 to indicate success

let prop = NamespaceProperties {
data: "namespace properties".to_string(),
};

Json(prop)
}
59 changes: 59 additions & 0 deletions src/handlers/table_handler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use axum::{
extract::{Json, Path},
http::StatusCode,
response::IntoResponse,
};


pub async fn list_tables(Path(namespace): Path<String>) -> Json<Vec<String>> {
// Dummy response for demonstration
let tables: Vec<String> = vec!["accounting".to_string(), "tax".to_string(), "paid".to_string()];
Json(tables)

}

pub async fn create_table(Path(namespace): Path<String>) -> impl IntoResponse {
// Logic to create a table in the given namespace
"Table created".to_string()
}

pub async fn register_table(Path(namespace): Path<String>) -> impl IntoResponse {
// Logic to register a table in the given namespace using metadata file location
"Table registered".to_string()
}

pub async fn load_table(Path((namespace, table)): Path<(String, String)>) -> impl IntoResponse {
// Logic to load a table from the catalog
Json(table)
}

pub async fn delete_table(Path((namespace, table)): Path<(String, String)>) -> impl IntoResponse {
// Logic to drop a table from the catalog
"Table dropped".to_string()
}

pub async fn table_exists(Path((namespace, table)): Path<(String, String)>) -> impl IntoResponse {
// Logic to check if a table exists within a given namespace
StatusCode::OK
}

#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct MetricsReport {

}

// Handler functions
pub async fn rename_table(table_rename: String) -> impl IntoResponse {
// Logic to rename a table from its current name to a new name
"Table renamed".to_string()
}

pub async fn report_metrics(Path((namespace, table)): Path<(String, String)>) -> impl IntoResponse {
// Logic to process metrics report
Json(table)
}

pub async fn find_tuple_location(Path((namespace, table, tuple_id)): Path<(String, String, String)>) -> impl IntoResponse {
// Logic to return the physical file location for a given tuple ID
format!("Physical file location for tuple ID {} of table {} in namespace {}.", tuple_id, table, namespace)
}
18 changes: 16 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
fn main() {
println!("hello world!");
mod routes;
mod dto;
mod handlers;
mod config;
mod tests;

use crate::config::parameters;

#[tokio::main]
async fn main() {
parameters::init();
let host = format!("0.0.0.0:{}", parameters::get("PORT"));

let listener = tokio::net::TcpListener::bind(host).await.unwrap();
let app = routes::root::routes();
axum::serve(listener, app).await.unwrap();
}
3 changes: 3 additions & 0 deletions src/routes/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod namespace;
pub mod table;
pub mod root;
13 changes: 13 additions & 0 deletions src/routes/namespace.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use axum::{ routing::{get, post, head, delete}, Router};
use crate::handlers::namespace_handler;

pub fn routes() -> Router<> {
let router = Router::new()
.route("/namespaces", get(namespace_handler::list_namespaces))
.route("/namespaces", post(namespace_handler::create_namespace))
.route("/namespace/:namespace", get(namespace_handler::load_namespace_metadata))
.route("/namespace/:namespace", head(namespace_handler::namespace_exists))
.route("/namespace/:namespace", delete(namespace_handler::drop_namespace))
.route("/namespace/:namespace/properties", post(namespace_handler::set_namespace_properties));
return router;
}
14 changes: 14 additions & 0 deletions src/routes/root.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use crate::routes::{namespace, table};
use axum::routing::IntoMakeService;
use axum::Router;
use tower_http::trace::TraceLayer;

pub fn routes() -> Router {

// merge the 2 routes
let app_router = Router::new()
.nest("/", table::routes())
.nest("/", namespace::routes());

app_router
}
18 changes: 18 additions & 0 deletions src/routes/table.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use axum::{ routing::{get, post, head, delete}, Router};
use crate::handlers::table_handler;


pub fn routes() -> Router<> {
let router = Router::new()
.route("/namespaces/:namespace/tables", get(table_handler::list_tables))
.route("/namespaces/:namespace/tables", post(table_handler::create_table))
.route("/namespaces/:namespace/register", post(table_handler::register_table))
.route("/namespaces/:namespace/tables/:table", get(table_handler::load_table))
.route("/namespaces/:namespace/tables/:table", delete(table_handler::delete_table))
.route("/namespaces/:namespace/tables/:table", head(table_handler::table_exists))
.route("/tables/rename", post(table_handler::rename_table))
.route("/namespaces/:namespace/tables/:table/metrics", post(table_handler::report_metrics))
.route("/namespaces/:namespace/tables/:table/find/:tuple_id", get(table_handler::find_tuple_location));

return router;
}
Empty file added src/tests/mod.rs
Empty file.
43 changes: 43 additions & 0 deletions src/tests/namespace_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use axum::{http::StatusCode, response::Json};
use axum::extract::Json as JsonExtractor;
use axum::handler::post;
use axum::routing::Router;
use serde_json::json;
use axum::test::extract;

use crate::{create_namespace, list_namespaces, Namespace};

#[tokio::test]
async fn test_list_namespaces() {
// Create a test router with the list_namespaces route
let app = Router::new().route("/namespaces", post(list_namespaces));

// Perform a request to the route
let response = axum::test::call(&app, axum::test::request::Request::post("/namespaces").body(()).unwrap()).await;

// Ensure that the response status code is OK
assert_eq!(response.status(), StatusCode::OK);

// Ensure that the response body contains the expected JSON data
let body = extract::<Json<Vec<String>>>(response.into_body()).await.unwrap();
assert_eq!(body.0, vec!["accounting", "tax", "paid"]);
}

#[tokio::test]
async fn test_create_namespace() {
// Create a test router with the create_namespace route
let app = Router::new().route("/namespaces", post(create_namespace));

// Create a JSON payload representing a new namespace
let payload = json!({});

// Perform a request to the route with the JSON payload
let response = axum::test::call(&app, axum::test::request::Request::post("/namespaces").body(payload.to_string()).unwrap()).await;

// Ensure that the response status code is OK
assert_eq!(response.status(), StatusCode::OK);

// Ensure that the response body contains the expected JSON data
let body = extract::<Json<Namespace>>(response.into_body()).await.unwrap();
assert_eq!(body, Json(Namespace {}));
}
Loading