Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std::net::IpAddr;

use crate::{
api::{FlagError, FlagsResponse},
request_handler::{process_request, FlagsQueryParams, RequestContext},
api::errors::FlagError,
api::handler::{process_request, FlagsQueryParams, RequestContext},
api::types::FlagsResponse,
router,
};
// TODO: stream this instead
Expand Down
Original file line number Diff line number Diff line change
@@ -1,60 +1,8 @@
use std::collections::HashMap;

use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use serde::{Deserialize, Serialize};
use thiserror::Error;

use crate::database::CustomDatabaseError;
use crate::redis::CustomRedisError;

#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
pub enum FlagsResponseCode {
Ok = 1,
}

#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
#[serde(untagged)]
pub enum FlagValue {
Boolean(bool),
String(String),
}

// TODO the following two types are kinda general, maybe we should move them to a shared module
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
#[serde(untagged)]
pub enum BooleanOrStringObject {
Boolean(bool),
Object(HashMap<String, String>),
}

#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
#[serde(untagged)]
pub enum BooleanOrBooleanObject {
Boolean(bool),
Object(HashMap<String, bool>),
}

#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct FlagsResponse {
pub error_while_computing_flags: bool,
pub feature_flags: HashMap<String, FlagValue>,
// TODO support the other fields in the payload
// pub config: HashMap<String, bool>,
// pub toolbar_params: HashMap<String, String>,
// pub is_authenticated: bool,
// pub supported_compression: Vec<String>,
// pub session_recording: bool,
// pub feature_flag_payloads: HashMap<String, String>,
// pub capture_performance: BooleanOrBooleanObject,
// #[serde(rename = "autocapture_opt_out")]
// pub autocapture_opt_out: bool,
// pub autocapture_exceptions: BooleanOrStringObject,
// pub surveys: bool,
// pub heatmaps: bool,
// pub site_apps: Vec<String>,
}
use crate::clients::{database::CustomDatabaseError, redis::CustomRedisError};

#[derive(Error, Debug)]
pub enum ClientFacingError {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use crate::{
api::{FlagError, FlagsResponse},
database::Client,
flag_definitions::FeatureFlagList,
flag_matching::{FeatureFlagMatcher, GroupTypeMappingCache},
flag_request::FlagRequest,
geoip::GeoIpClient,
api::errors::FlagError,
api::types::FlagsResponse,
clients::database::Client,
clients::geoip::GeoIpClient,
flags::flag_matching::{FeatureFlagMatcher, GroupTypeMappingCache},
flags::flag_models::FeatureFlagList,
flags::flag_request::FlagRequest,
router,
};
use axum::{extract::State, http::HeaderMap};
Expand Down Expand Up @@ -108,18 +109,15 @@ pub async fn process_request(context: RequestContext) -> Result<FlagsResponse, F
let hash_key_override = request.anon_distinct_id.clone();

let feature_flags_from_cache_or_pg = request
.get_flags_from_cache_or_pg(team_id, state.redis.clone(), state.postgres_reader.clone())
.get_flags_from_cache_or_pg(team_id, &state.redis, &state.postgres_reader)
.await?;

let postgres_reader_dyn: Arc<dyn Client + Send + Sync> = state.postgres_reader.clone();
let postgres_writer_dyn: Arc<dyn Client + Send + Sync> = state.postgres_writer.clone();

let evaluation_context = FeatureFlagEvaluationContextBuilder::default()
.team_id(team_id)
.distinct_id(distinct_id)
.feature_flags(feature_flags_from_cache_or_pg)
.postgres_reader(postgres_reader_dyn)
.postgres_writer(postgres_writer_dyn)
.postgres_reader(state.postgres_reader.clone())
.postgres_writer(state.postgres_writer.clone())
.person_property_overrides(person_property_overrides)
.group_property_overrides(group_property_overrides)
.groups(groups)
Expand Down Expand Up @@ -253,10 +251,13 @@ fn decompress_gzip(compressed: Bytes) -> Result<Bytes, FlagError> {
#[cfg(test)]
mod tests {
use crate::{
api::FlagValue,
api::types::FlagValue,
config::Config,
flag_definitions::{FeatureFlag, FlagFilters, FlagGroupType, OperatorType, PropertyFilter},
test_utils::{insert_new_team_in_pg, setup_pg_reader_client, setup_pg_writer_client},
flags::flag_models::{FeatureFlag, FlagFilters, FlagGroupType},
properties::property_models::{OperatorType, PropertyFilter},
utils::test_utils::{
insert_new_team_in_pg, setup_pg_reader_client, setup_pg_writer_client,
},
};

use super::*;
Expand Down Expand Up @@ -374,6 +375,7 @@ mod tests {
operator: Some(OperatorType::Exact),
prop_type: "person".to_string(),
group_type_index: None,
negation: None,
}]),
rollout_percentage: Some(100.0), // Set to 100% to ensure it's always on
variant: None,
Expand Down Expand Up @@ -627,6 +629,7 @@ mod tests {
operator: Some(OperatorType::Exact),
prop_type: "group".to_string(),
group_type_index: Some(0),
negation: None,
}]),
rollout_percentage: Some(100.0),
variant: None,
Expand Down
4 changes: 4 additions & 0 deletions rust/feature-flags/src/api/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub mod endpoint;
pub mod errors;
pub mod handler;
pub mod types;
21 changes: 21 additions & 0 deletions rust/feature-flags/src/api/types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
pub enum FlagsResponseCode {
Ok = 1,
}

#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
#[serde(untagged)]
pub enum FlagValue {
Boolean(bool),
String(String),
}

#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct FlagsResponse {
pub error_while_computing_flags: bool,
pub feature_flags: HashMap<String, FlagValue>,
}
3 changes: 3 additions & 0 deletions rust/feature-flags/src/clients/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod database;
pub mod geoip;
pub mod redis;
74 changes: 74 additions & 0 deletions rust/feature-flags/src/cohorts/cohort_models.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use crate::properties::property_models::PropertyFilter;
use serde::{Deserialize, Serialize};
use sqlx::FromRow;

#[derive(Debug, FromRow)]
pub struct CohortRow {
pub id: i32,
pub name: String,
pub description: Option<String>,
pub team_id: i32,
pub deleted: bool,
pub filters: serde_json::Value,
pub query: Option<serde_json::Value>,
pub version: Option<i32>,
pub pending_version: Option<i32>,
pub count: Option<i32>,
pub is_calculating: bool,
pub is_static: bool,
pub errors_calculating: i32,
pub groups: serde_json::Value,
pub created_by_id: Option<i32>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Cohort {
pub id: i32,
pub name: String,
pub description: Option<String>,
pub team_id: i32,
pub deleted: bool,
pub filters: serde_json::Value,
pub query: Option<serde_json::Value>,
pub version: Option<i32>,
pub pending_version: Option<i32>,
pub count: Option<i32>,
pub is_calculating: bool,
pub is_static: bool,
pub errors_calculating: i32,
pub groups: serde_json::Value,
pub created_by_id: Option<i32>,
}

pub type CohortId = i32;

pub enum CohortOrEmpty {
Cohort(Cohort),
Empty,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "UPPERCASE")]
pub enum CohortPropertyType {
AND,
OR,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct CohortProperty {
pub properties: InnerCohortProperty,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct InnerCohortProperty {
#[serde(rename = "type")]
pub prop_type: CohortPropertyType,
pub values: Vec<CohortValues>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct CohortValues {
#[serde(rename = "type")]
pub prop_type: String,
pub values: Vec<PropertyFilter>,
}
Loading