use crate::{
filter::{Filter, IndexScanFilter},
index::IndexDescriptor,
SortOrder,
};
use icu_collator::options::CollatorOptions;
use icu_collator::CollatorPreferences;
use std::collections::HashMap;
use std::sync::Arc;
#[derive(Clone)]
pub struct FindPlan {
inner: Arc<FindPlanInner>,
}
impl FindPlan {
pub(crate) fn new() -> Self {
FindPlan {
inner: Arc::new(FindPlanInner::new()),
}
}
pub fn by_id_filter(&self) -> Option<Filter> {
self.inner.by_id_filter.clone()
}
pub fn index_scan_filter(&self) -> Option<IndexScanFilter> {
self.inner.index_scan_filter.clone()
}
pub fn full_scan_filter(&self) -> Option<Filter> {
self.inner.full_scan_filter.clone()
}
pub fn index_descriptor(&self) -> Option<IndexDescriptor> {
self.inner.index_descriptor.clone()
}
pub fn index_scan_order(&self) -> Option<HashMap<String, bool>> {
self.inner.index_scan_order.clone()
}
pub fn blocking_sort_order(&self) -> Option<Vec<(String, SortOrder)>> {
self.inner.blocking_sort_order.clone()
}
pub fn skip(&self) -> Option<u64> {
self.inner.skip
}
pub fn limit(&self) -> Option<u64> {
self.inner.limit
}
pub fn distinct(&self) -> bool {
self.inner.distinct
}
pub fn collator_options(&self) -> Option<CollatorOptions> {
self.inner.collator_options
}
pub fn collator_preferences(&self) -> Option<CollatorPreferences> {
self.inner.collator_preferences
}
pub fn sub_plans(&self) -> Option<Vec<FindPlan>> {
self.inner.sub_plans.clone()
}
pub fn add_sub_plan(&mut self, sub_plan: FindPlan) {
if let Some(inner) = Arc::get_mut(&mut self.inner) {
inner.sub_plans.get_or_insert_with(Vec::new).push(sub_plan);
}
}
pub(crate) fn set_by_id_filter(&mut self, filter: Filter) {
if let Some(inner) = Arc::get_mut(&mut self.inner) {
inner.by_id_filter = Some(filter);
}
}
pub(crate) fn set_index_scan_filter(&mut self, filter: IndexScanFilter) {
if let Some(inner) = Arc::get_mut(&mut self.inner) {
inner.index_scan_filter = Some(filter);
}
}
pub(crate) fn set_full_scan_filter(&mut self, filter: Filter) {
if let Some(inner) = Arc::get_mut(&mut self.inner) {
inner.full_scan_filter = Some(filter);
}
}
pub(crate) fn set_index_descriptor(&mut self, descriptor: IndexDescriptor) {
if let Some(inner) = Arc::get_mut(&mut self.inner) {
inner.index_descriptor = Some(descriptor);
}
}
pub(crate) fn set_blocking_sort_order(&mut self, order: Vec<(String, SortOrder)>) {
if let Some(inner) = Arc::get_mut(&mut self.inner) {
inner.blocking_sort_order = Some(order);
}
}
pub(crate) fn set_skip(&mut self, skip: u64) {
if let Some(inner) = Arc::get_mut(&mut self.inner) {
inner.skip = Some(skip);
}
}
pub(crate) fn set_limit(&mut self, limit: u64) {
if let Some(inner) = Arc::get_mut(&mut self.inner) {
inner.limit = Some(limit);
}
}
pub(crate) fn set_distinct(&mut self, distinct: bool) {
if let Some(inner) = Arc::get_mut(&mut self.inner) {
inner.distinct = distinct;
}
}
pub(crate) fn set_collator_options(&mut self, options: CollatorOptions) {
if let Some(inner) = Arc::get_mut(&mut self.inner) {
inner.collator_options = Some(options);
}
}
pub(crate) fn set_collator_preferences(&mut self, preferences: CollatorPreferences) {
if let Some(inner) = Arc::get_mut(&mut self.inner) {
inner.collator_preferences = Some(preferences);
}
}
}
pub(crate) struct FindPlanInner {
pub(crate) by_id_filter: Option<Filter>,
pub(crate) index_scan_filter: Option<IndexScanFilter>,
pub(crate) full_scan_filter: Option<Filter>,
pub(crate) index_descriptor: Option<IndexDescriptor>,
pub(crate) index_scan_order: Option<HashMap<String, bool>>,
pub(crate) blocking_sort_order: Option<Vec<(String, SortOrder)>>,
pub(crate) skip: Option<u64>,
pub(crate) limit: Option<u64>,
pub(crate) distinct: bool,
pub(crate) collator_options: Option<CollatorOptions>,
pub(crate) collator_preferences: Option<CollatorPreferences>,
pub(crate) sub_plans: Option<Vec<FindPlan>>,
}
impl FindPlanInner {
fn new() -> Self {
FindPlanInner {
by_id_filter: None,
index_scan_filter: None,
full_scan_filter: None,
index_descriptor: None,
index_scan_order: None,
blocking_sort_order: None,
skip: None,
limit: None,
distinct: false,
collator_options: None,
collator_preferences: None,
sub_plans: None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add_single_sub_plan() {
let mut plan = FindPlan::new();
assert!(plan.sub_plans().is_none());
let sub_plan = FindPlan::new();
plan.add_sub_plan(sub_plan);
assert!(plan.sub_plans().is_some());
let plans = plan.sub_plans().unwrap();
assert_eq!(plans.len(), 1);
}
#[test]
fn test_add_multiple_sub_plans() {
let mut plan = FindPlan::new();
for i in 0..5 {
let mut sub_plan = FindPlan::new();
sub_plan.set_skip(i as u64);
plan.add_sub_plan(sub_plan);
}
let plans = plan.sub_plans().unwrap();
assert_eq!(plans.len(), 5);
for (i, sub_plan) in plans.iter().enumerate() {
assert_eq!(sub_plan.skip(), Some(i as u64));
}
}
#[test]
fn test_add_sub_plan_idempotent_initialization() {
let mut plan1 = FindPlan::new();
let mut plan2 = FindPlan::new();
let sub_plan1 = FindPlan::new();
let sub_plan2 = FindPlan::new();
plan1.add_sub_plan(sub_plan1);
plan1.add_sub_plan(sub_plan2);
plan2.add_sub_plan(FindPlan::new());
assert_eq!(plan1.sub_plans().unwrap().len(), 2);
assert_eq!(plan2.sub_plans().unwrap().len(), 1);
}
#[test]
fn test_add_sub_plan_preserves_existing_data() {
let mut parent_plan = FindPlan::new();
parent_plan.set_skip(10);
parent_plan.set_limit(20);
let mut sub_plan = FindPlan::new();
sub_plan.set_distinct(true);
parent_plan.add_sub_plan(sub_plan);
assert_eq!(parent_plan.skip(), Some(10));
assert_eq!(parent_plan.limit(), Some(20));
let plans = parent_plan.sub_plans().unwrap();
assert_eq!(plans.len(), 1);
assert!(plans[0].distinct());
}
#[test]
fn test_add_sub_plan_thread_safety_simulation() {
let mut plans_vec = vec![FindPlan::new(); 3];
for parent_plan in &mut plans_vec {
for _ in 0..10 {
let sub_plan = FindPlan::new();
parent_plan.add_sub_plan(sub_plan);
}
}
let verification_plans = plans_vec.clone();
for plan in &verification_plans {
let sub_plans = plan.sub_plans();
if let Some(plans) = sub_plans {
assert_eq!(plans.len(), 10);
}
}
}
}