Skip to content

Commit

Permalink
feat: config version implementaion
Browse files Browse the repository at this point in the history
  • Loading branch information
Pratik Mishra authored and Pratik Mishra committed May 17, 2024
1 parent 0c9d070 commit 3ae53b5
Show file tree
Hide file tree
Showing 25 changed files with 457 additions and 187 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-- This file should undo anything in `up.sql`
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
-- Your SQL goes here
-- Name: functions; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.config_versions (
id bigint PRIMARY KEY,
config json NOT NULL,
config_hash TEXT NOT NULL,
tags varchar(100)[] check (array_position(tags, null) is null),
created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
);
--
77 changes: 62 additions & 15 deletions crates/context_aware_config/src/api/config/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use super::helpers::{

use super::types::Config;
use crate::db::schema::{
contexts::dsl as ctxt, default_configs::dsl as def_conf, event_log::dsl as event_log,
config_versions::dsl as config_versions, contexts::dsl as ctxt,
default_configs::dsl as def_conf, event_log::dsl as event_log,
};
use actix_http::header::{HeaderName, HeaderValue};
use actix_web::{get, web::Query, HttpRequest, HttpResponse, Scope};
Expand All @@ -18,11 +19,12 @@ use diesel::{
r2d2::{ConnectionManager, PooledConnection},
ExpressionMethods, PgConnection, QueryDsl, RunQueryDsl,
};
use serde_json::{json, Map, Value};
use service_utils::service::types::DbConnection;
use service_utils::{bad_argument, db_error, unexpected_error};
use serde_json::{from_value, json, Map, Value};
use service_utils::{
bad_argument, db_error, result as superposition, service::types::DbConnection,
unexpected_error,
};

use service_utils::result as superposition;
use uuid::Uuid;

pub fn endpoints() -> Scope {
Expand Down Expand Up @@ -98,24 +100,66 @@ fn is_not_modified(max_created_at: Option<NaiveDateTime>, req: &HttpRequest) ->
max_created_at.is_some() && parsed_max <= last_modified
}

async fn generate_cac(
pub fn generate_config_from_version(
version: Option<Value>,
conn: &mut PooledConnection<ConnectionManager<PgConnection>>,
) -> superposition::Result<Config> {
let config = match version {
None => config_versions::config_versions
.select(config_versions::config)
.order_by(config_versions::created_at.desc())
.first::<Value>(conn)
.map_err(|err| {
log::error!("failed to fetch config with error: {}", err);
db_error!(err)
}),
Some(version_val) => {
let version_id = from_value::<i64>(version_val).map_err(|e| {
log::error!("failed to decode version_id as integer: {}", e);
bad_argument!("version_id is not of type integer")
})?;
config_versions::config_versions
.select(config_versions::config)
.filter(config_versions::id.eq(version_id))
.get_result::<Value>(conn)
.map_err(|err| {
log::error!("failed to fetch config with error: {}", err);
db_error!(err)
})
}
}?;

serde_json::from_value::<Config>(config).map_err(|err| {
log::error!("failed to decode config: {}", err);
unexpected_error!("failed to decode config")
})
}
pub fn generate_cac(
conn: &mut PooledConnection<ConnectionManager<PgConnection>>,
) -> superposition::Result<Config> {
let contexts_vec = ctxt::contexts
.select((ctxt::id, ctxt::value, ctxt::override_id, ctxt::override_))
.select((
ctxt::id,
ctxt::value,
ctxt::priority,
ctxt::override_id,
ctxt::override_,
))
.order_by((ctxt::priority.asc(), ctxt::created_at.asc()))
.load::<(String, Value, String, Value)>(conn)
.load::<(String, Value, i32, String, Value)>(conn)
.map_err(|err| {
log::error!("failed to fetch contexts with error: {}", err);
db_error!(err)
})?;

let (contexts, overrides) = contexts_vec.into_iter().fold(
(Vec::new(), Map::new()),
|(mut ctxts, mut overrides), (id, condition, override_id, override_)| {
|(mut ctxts, mut overrides),
(id, condition, priority_, override_id, override_)| {
let ctxt = super::types::Context {
id,
condition,
priority: priority_,
override_with_keys: [override_id.to_owned()],
};
ctxts.push(ctxt);
Expand Down Expand Up @@ -177,12 +221,13 @@ async fn get(
query_params_map.insert(
key,
value
.parse::<i32>()
.parse::<i64>()
.map_or_else(|_| json!(value), |int_val| json!(int_val)),
);
}

let mut config = generate_cac(&mut conn).await?;
let mut config =
generate_config_from_version(query_params_map.remove("version"), &mut conn)?;
if let Some(prefix) = query_params_map.get("prefix") {
let prefix_list: HashSet<&str> = prefix
.as_str()
Expand Down Expand Up @@ -225,7 +270,7 @@ async fn get_resolved_config(
query_params_map.insert(
item.0,
item.1
.parse::<i32>()
.parse::<i64>()
.map_or_else(|_| json!(item.1), |int_val| json!(int_val)),
);
}
Expand All @@ -240,7 +285,8 @@ async fn get_resolved_config(
return Ok(HttpResponse::NotModified().finish());
}

let res = generate_cac(&mut conn).await?;
let res =
generate_config_from_version(query_params_map.remove("version"), &mut conn)?;

let cac_client_contexts = res
.contexts
Expand Down Expand Up @@ -309,11 +355,12 @@ async fn get_filtered_config(
query_params_map.insert(
key,
value
.parse::<i32>()
.parse::<i64>()
.map_or_else(|_| json!(value), |int_val| json!(int_val)),
);
}
let config = generate_cac(&mut conn).await?;
let config =
generate_config_from_version(query_params_map.remove("version"), &mut conn)?;
let contexts = config.contexts;

let filtered_context = filter_context(&contexts, &query_params_map)?;
Expand Down
2 changes: 1 addition & 1 deletion crates/context_aware_config/src/api/config/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mod handlers;
pub mod handlers;
mod types;
pub use handlers::endpoints;
mod helpers;
7 changes: 4 additions & 3 deletions crates/context_aware_config/src/api/config/types.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
use serde::Serialize;
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};

#[derive(Serialize)]
#[derive(Serialize, Deserialize)]
pub struct Config {
pub contexts: Vec<Context>,
pub overrides: Map<String, Value>,
pub default_configs: Map<String, Value>,
}

#[derive(Serialize, Clone)]
#[derive(Serialize, Clone, Deserialize)]
pub struct Context {
pub id: String,
pub condition: Value,
pub priority: i32,
pub override_with_keys: [String; 1],
}

0 comments on commit 3ae53b5

Please sign in to comment.