248 lines
8.3 KiB
Rust
248 lines
8.3 KiB
Rust
use rayon::iter::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator};
|
|
use serde::{Deserialize, Serialize};
|
|
use serde_json::Value;
|
|
use std::collections::BTreeMap;
|
|
use std::io::Read;
|
|
use std::path::PathBuf;
|
|
use std::sync::Arc;
|
|
|
|
use crate::models::recipe::*;
|
|
use crate::recipe_functions::common::{self};
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
pub struct RecipeListChange {
|
|
pub new_value: Value,
|
|
pub raw_old: Vec<crate::models::recipe::RecipeList>,
|
|
pub raw_new: Vec<crate::models::recipe::RecipeList>,
|
|
/// for sub menu
|
|
pub sub_changes: BTreeMap<String, Value>,
|
|
}
|
|
|
|
impl RecipeListChange {
|
|
pub fn get_changes(&mut self) {
|
|
let old_length = self.raw_old.len();
|
|
let new_length = self.raw_new.len();
|
|
|
|
let is_match_length = old_length == new_length;
|
|
let length_for_checking = if is_match_length {
|
|
old_length
|
|
} else {
|
|
if old_length < new_length {
|
|
new_length
|
|
} else {
|
|
old_length
|
|
}
|
|
};
|
|
|
|
let mut checked: Vec<Vec<String>> = vec![Vec::new(); length_for_checking];
|
|
|
|
for ci in 0..length_for_checking {
|
|
let current_repl = (self.raw_old.get(ci), self.raw_new.get(ci));
|
|
if current_repl.0.is_some() && current_repl.1.is_some() {
|
|
let old_repl = current_repl.0.unwrap();
|
|
let new_repl = current_repl.1.unwrap();
|
|
|
|
let diff = old_repl.compare(new_repl);
|
|
checked[ci] = diff;
|
|
} else if current_repl.0.is_none() && current_repl.1.is_some() {
|
|
// new value
|
|
checked[ci] = current_repl
|
|
.1
|
|
.unwrap()
|
|
.to_map()
|
|
.as_object()
|
|
.unwrap()
|
|
.keys()
|
|
.map(|k| k.to_string())
|
|
.collect();
|
|
} else if current_repl.0.is_some() && current_repl.1.is_none() {
|
|
// new value does not exist
|
|
checked[ci] = current_repl
|
|
.0
|
|
.unwrap()
|
|
.to_map()
|
|
.as_object()
|
|
.unwrap()
|
|
.keys()
|
|
.map(|k| format!("old.{}", k).to_string())
|
|
.collect();
|
|
}
|
|
}
|
|
|
|
self.new_value = serde_json::to_value(checked).unwrap();
|
|
}
|
|
}
|
|
|
|
pub struct ShardingRecipe {
|
|
pub category_map: BTreeMap<String, Value>,
|
|
}
|
|
|
|
impl ShardingRecipe {
|
|
pub fn build(data: BTreeMap<String, Value>) -> Self {
|
|
let keylist: Vec<String> = data.keys().map(|k| k.to_string()).collect();
|
|
let mut category_map = BTreeMap::new();
|
|
|
|
for key in keylist {
|
|
let kspl: Vec<&str> = key.split("-").collect();
|
|
|
|
if kspl.len() > 3 {
|
|
let category = kspl[1].to_string();
|
|
|
|
if !category_map.contains_key(&category.clone()) {
|
|
category_map.insert(category.clone(), serde_json::json!(Vec::<Value>::new()));
|
|
}
|
|
|
|
category_map
|
|
.get_mut(&category.clone())
|
|
.unwrap()
|
|
.as_array_mut()
|
|
.unwrap()
|
|
.push(serde_json::to_value(data.get(&key).unwrap()).unwrap());
|
|
}
|
|
}
|
|
|
|
Self { category_map }
|
|
}
|
|
}
|
|
|
|
/// break down recipe(s) in the folder into mapping,
|
|
/// tracking diff between fields. (This does not compare other fields than Recipe01)
|
|
pub fn build_recipe_shardings(source: PathBuf) -> ShardingRecipe {
|
|
let files = common::get_all_files_in_directory(source.as_path().to_str().unwrap());
|
|
let known_latest_version = format!("{}/version", source.as_path().to_str().unwrap());
|
|
let mut latest_version_string = String::new();
|
|
std::fs::File::open(known_latest_version)
|
|
.unwrap()
|
|
.read_to_string(&mut latest_version_string)
|
|
.unwrap();
|
|
|
|
let latest_version = latest_version_string.parse::<i64>().unwrap();
|
|
|
|
let mut recipes: Vec<Recipe> = files
|
|
.par_iter()
|
|
.filter(|file| file.ends_with("json") && file.contains("coffeethai02"))
|
|
.map(|file| common::create_recipe_model_from_file(file.to_string()))
|
|
.collect();
|
|
|
|
// ascending order a.compare(b)
|
|
recipes.sort_by(|a, b| {
|
|
let version_a = a.MachineSetting.get_config_number().as_i64().unwrap();
|
|
let version_b = b.MachineSetting.get_config_number().as_i64().unwrap();
|
|
|
|
version_a.cmp(&version_b)
|
|
});
|
|
|
|
// Structure
|
|
// { productCode: { version: [ Option<RecipeChange> ] } }
|
|
let mut shards = BTreeMap::new();
|
|
|
|
if recipes.is_empty() {
|
|
eprintln!("recipes get empty!!!");
|
|
} else {
|
|
println!("recipes cnt = {}", recipes.len());
|
|
}
|
|
|
|
let base_version: i64 = latest_version;
|
|
let base_recipe: Vec<Recipe> = recipes
|
|
.iter()
|
|
.filter(|r| {
|
|
r.MachineSetting
|
|
.get_config_number()
|
|
.as_i64()
|
|
.unwrap()
|
|
.eq(&base_version)
|
|
})
|
|
.cloned()
|
|
.collect();
|
|
|
|
shards = base_recipe
|
|
.first()
|
|
.unwrap()
|
|
.Recipe01
|
|
.par_iter()
|
|
.map(|rp1| {
|
|
let mut sub_changes = BTreeMap::new();
|
|
|
|
if rp1.clone().SubMenu.is_some() {
|
|
let subs = rp1.clone().SubMenu.unwrap().clone();
|
|
|
|
sub_changes = subs
|
|
.par_iter()
|
|
.map(|sub1| {
|
|
let change_sub = RecipeListChange {
|
|
new_value: Value::Null,
|
|
raw_new: sub1.recipes.clone(),
|
|
raw_old: sub1.recipes.clone(),
|
|
sub_changes: BTreeMap::new(),
|
|
};
|
|
|
|
let mut change_sub_map = BTreeMap::new();
|
|
change_sub_map.insert(base_version, change_sub.clone());
|
|
recipes.iter().for_each(|rc| {
|
|
// clone change
|
|
let mut change_sub_clone = change_sub.clone();
|
|
|
|
match rc.search_pd_by_no_country_code(sub1.clone().productCode) {
|
|
Some(spd) => {
|
|
change_sub_clone.raw_new = spd.clone().recipes;
|
|
}
|
|
None => {}
|
|
};
|
|
change_sub_clone.get_changes();
|
|
change_sub_map.insert(
|
|
rc.MachineSetting
|
|
.get_config_number()
|
|
.as_i64()
|
|
.unwrap()
|
|
.clone(),
|
|
change_sub_clone.clone(),
|
|
);
|
|
});
|
|
|
|
(
|
|
sub1.clone().productCode,
|
|
serde_json::to_value(change_sub_map).unwrap(),
|
|
)
|
|
})
|
|
.collect();
|
|
}
|
|
|
|
let change = RecipeListChange {
|
|
new_value: Value::Null,
|
|
raw_old: rp1.recipes.clone(),
|
|
raw_new: rp1.recipes.clone(),
|
|
sub_changes,
|
|
};
|
|
|
|
let mut change_map = BTreeMap::new();
|
|
change_map.insert(base_version, change.clone());
|
|
recipes.iter().for_each(|rc| {
|
|
// clone change
|
|
let mut change_clone = change.clone();
|
|
|
|
match rc.search_pd_by_no_country_code(rp1.clone().productCode) {
|
|
Some(pdr) => {
|
|
change_clone.raw_new = pdr.clone().recipes;
|
|
}
|
|
None => {}
|
|
}
|
|
change_clone.get_changes();
|
|
change_map.insert(
|
|
rc.MachineSetting
|
|
.get_config_number()
|
|
.as_i64()
|
|
.unwrap()
|
|
.clone(),
|
|
change_clone,
|
|
);
|
|
});
|
|
|
|
(
|
|
rp1.clone().productCode,
|
|
serde_json::to_value(change_map).unwrap(),
|
|
)
|
|
})
|
|
.collect();
|
|
|
|
ShardingRecipe::build(shards)
|
|
}
|