Refactor and improve

This commit is contained in:
Andras Schmelczer 2026-02-03 20:26:57 +00:00
parent 1f148b2185
commit 242acff987
22 changed files with 754 additions and 1053 deletions

View file

@ -9,15 +9,12 @@ use serde::{Deserialize, Serialize};
use tracing::{info, warn};
use crate::consts::{
DEFAULT_PROPERTIES_LIMIT, ENUM_NULL, H3_PRECOMPUTE_MAX, H3_REQUEST_MAX, H3_REQUEST_MIN,
DEFAULT_PROPERTIES_LIMIT, H3_PRECOMPUTE_MAX, H3_REQUEST_MAX, H3_REQUEST_MIN,
MAX_PROPERTIES_LIMIT,
};
use crate::data::EnumFeatureData;
use crate::filter::{parse_filters, row_passes_filters};
use crate::parsing::{h3_cell_bounds, parse_filters, row_passes_filters};
use crate::state::AppState;
use super::parse::h3_cell_bounds;
#[derive(Deserialize)]
pub struct HexagonPropertiesParams {
pub h3: String,
@ -66,21 +63,25 @@ fn non_empty_string(text: &str) -> Option<String> {
}
}
/// Look up an enum feature value by trying multiple possible column names.
/// Uses the unified feature model: enum values stored as f32 indices in feature_data.
fn lookup_enum_value(
enum_features: &[EnumFeatureData],
enum_data: &[u8],
num_enums: usize,
enum_idx: &FxHashMap<String, usize>,
feature_names: &[String],
feature_data: &[f32],
num_features: usize,
enum_values: &FxHashMap<usize, Vec<String>>,
row: usize,
names: &[&str],
) -> Option<String> {
for name in names {
if let Some(&feature_index) = enum_idx.get(*name) {
let enum_feature = &enum_features[feature_index];
let data_index = enum_data[row * num_enums + feature_index];
if data_index != ENUM_NULL {
if let Some(value) = enum_feature.values.get(data_index as usize) {
return Some(value.clone());
if let Some(feat_idx) = feature_names.iter().position(|feat_name| feat_name == *name) {
if let Some(values) = enum_values.get(&feat_idx) {
let value = feature_data[row * num_features + feat_idx];
if value.is_finite() {
let idx = value as usize;
if let Some(str_value) = values.get(idx) {
return Some(str_value.clone());
}
}
}
}
@ -120,7 +121,7 @@ pub async fn get_hexagon_properties(
let (parsed_filters, parsed_enum_filters) = parse_filters(
params.filters.as_deref(),
&state.data.feature_names,
&state.data.enum_features,
&state.data.enum_values,
);
let num_filters = parsed_filters.len() + parsed_enum_filters.len();
@ -131,10 +132,9 @@ pub async fn get_hexagon_properties(
.map_err(|err| format!("Invalid H3 resolution {}: {}", resolution, err))?;
let need_parent = resolution < H3_PRECOMPUTE_MAX;
let num_features = state.data.num_features;
let num_enums = state.data.num_enums;
let feature_data = &state.data.feature_data;
let enum_data_flat = &state.data.enum_data;
let enum_features = &state.data.enum_features;
let feature_names = &state.data.feature_names;
let enum_values = &state.data.enum_values;
let (min_lat, min_lon, max_lat, max_lon) = h3_cell_bounds(cell, 0.001);
@ -162,8 +162,6 @@ pub async fn get_hexagon_properties(
&parsed_enum_filters,
feature_data,
num_features,
enum_data_flat,
num_enums,
)
{
matching_rows.push(row);
@ -185,7 +183,11 @@ pub async fn get_hexagon_properties(
.map(|&row| {
let mut features = FxHashMap::default();
let base = row * num_features;
for (feat_idx, feat_name) in state.data.feature_names.iter().enumerate() {
for (feat_idx, feat_name) in feature_names.iter().enumerate() {
// Skip enum features in the generic features map
if enum_values.contains_key(&feat_idx) {
continue;
}
let value = feature_data[base + feat_idx];
if value.is_finite() {
features.insert(feat_name.clone(), value);
@ -197,42 +199,42 @@ pub async fn get_hexagon_properties(
postcode: non_empty_string(state.data.postcode(row)),
is_construction_date_approximate: Some(state.data.is_approx_build_date(row)),
property_type: lookup_enum_value(
enum_features,
enum_data_flat,
num_enums,
&state.enum_name_to_idx,
feature_names,
feature_data,
num_features,
enum_values,
row,
&["Property type", "epc_property_type", "pp_property_type"],
),
built_form: lookup_enum_value(
enum_features,
enum_data_flat,
num_enums,
&state.enum_name_to_idx,
feature_names,
feature_data,
num_features,
enum_values,
row,
&["Property type/built form", "built_form"],
),
duration: lookup_enum_value(
enum_features,
enum_data_flat,
num_enums,
&state.enum_name_to_idx,
feature_names,
feature_data,
num_features,
enum_values,
row,
&["Leashold/Freehold", "duration"],
),
current_energy_rating: lookup_enum_value(
enum_features,
enum_data_flat,
num_enums,
&state.enum_name_to_idx,
feature_names,
feature_data,
num_features,
enum_values,
row,
&["Current energy rating", "current_energy_rating"],
),
potential_energy_rating: lookup_enum_value(
enum_features,
enum_data_flat,
num_enums,
&state.enum_name_to_idx,
feature_names,
feature_data,
num_features,
enum_values,
row,
&["Potential energy rating", "potential_energy_rating"],
),