all is well
Some checks failed
Build and publish Docker image / build-and-push (push) Failing after 7m0s
CI / Check (push) Failing after 7m9s

This commit is contained in:
Andras Schmelczer 2026-05-17 17:20:19 +01:00
parent eac1bd0d13
commit 2f149503bb
53 changed files with 1543 additions and 354 deletions

View file

@ -13,12 +13,10 @@ pub const GRID_CELL_SIZE: f32 = 0.01;
pub const MAX_CELLS_PER_REQUEST: usize = 200000;
pub const MAX_POIS_PER_REQUEST: usize = 3000;
pub const DEFAULT_PROPERTIES_LIMIT: usize = 100;
pub const DEFAULT_ACTUAL_LISTINGS_LIMIT: usize = 500;
pub const MAX_ACTUAL_LISTINGS_LIMIT: usize = 2000;
pub const MAX_PLACES_LIMIT: usize = 20;
pub const DEFAULT_PLACES_LIMIT: usize = 7;
pub const MAX_PRICE_HISTORY_POINTS: usize = 5000;
pub const PROPERTIES_LIMIT: usize = 100;
pub const ACTUAL_LISTINGS_LIMIT: usize = 500;
pub const PLACES_LIMIT: usize = 20;
pub const PRICE_HISTORY_POINTS_LIMIT: usize = 5000;
pub const POSTCODE_SEARCH_OFFSET: f64 = 0.02;
pub const AI_FILTERS_MAX_TOKENS: usize = 2000;

View file

@ -30,6 +30,16 @@ const GROCERY_DASHBOARD_CATEGORIES: &[&str] = &[
"Budgens",
"Centra",
"Co-op",
"Central England Co-operative",
"Chelmsford Star Co-operative Society",
"East of England Co-operative",
"Heart of England Co-operative",
"Lincolnshire Co-operative",
"Midcounties Co-operative",
"Scottish Midland Co-operative",
"Tamworth Co-operative Society",
"The Radstock Co-operative Society",
"The Southern Co-operative",
"COOK",
"Costco",
"Dunnes Stores",

View file

@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
use tracing::info;
use crate::api_error::ApiError;
use crate::consts::{DEFAULT_ACTUAL_LISTINGS_LIMIT, MAX_ACTUAL_LISTINGS_LIMIT};
use crate::consts::ACTUAL_LISTINGS_LIMIT;
use crate::data::ActualListing;
use crate::features::property_level_feature_names;
use crate::parsing::{
@ -24,9 +24,6 @@ pub struct ActualListingsParams {
filters: Option<String>,
/// Pipe-separated travel time entries: `mode:slug|mode:slug:min:max`
travel: Option<String>,
/// Page size — defaults to DEFAULT_ACTUAL_LISTINGS_LIMIT, capped at
/// MAX_ACTUAL_LISTINGS_LIMIT.
limit: Option<usize>,
/// Number of results to skip. Defaults to 0.
offset: Option<usize>,
}
@ -35,7 +32,6 @@ pub struct ActualListingsParams {
pub struct ActualListingsResponse {
pub listings: Vec<ActualListing>,
pub total: usize,
pub limit: usize,
pub offset: usize,
pub truncated: bool,
}
@ -45,16 +41,12 @@ pub async fn get_actual_listings(
Query(params): Query<ActualListingsParams>,
) -> Result<Json<ActualListingsResponse>, ApiError> {
let state = shared.load_state();
let limit = params
.limit
.unwrap_or(DEFAULT_ACTUAL_LISTINGS_LIMIT)
.min(MAX_ACTUAL_LISTINGS_LIMIT);
let limit = ACTUAL_LISTINGS_LIMIT;
let offset = params.offset.unwrap_or(0);
let Some(actual_listings) = state.actual_listings.clone() else {
return Ok(Json(ActualListingsResponse {
listings: Vec::new(),
total: 0,
limit,
offset,
truncated: false,
}));
@ -162,7 +154,6 @@ pub async fn get_actual_listings(
Ok(ActualListingsResponse {
listings,
total: total_matching,
limit,
offset,
truncated,
})

View file

@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
use tracing::info;
use crate::api_error::ApiError;
use crate::consts::{DEFAULT_PLACES_LIMIT, MAX_PLACES_LIMIT};
use crate::consts::PLACES_LIMIT;
use crate::data::{normalize_search_text, slugify};
use crate::state::SharedState;
@ -42,7 +42,6 @@ pub struct PlacesResponse {
#[allow(clippy::min_ident_chars)]
pub struct PlacesParams {
q: String,
limit: Option<usize>,
/// If set, only return places that have travel time data for this mode.
mode: Option<String>,
}
@ -105,10 +104,7 @@ pub async fn get_places(
params.q
};
let limit = params
.limit
.unwrap_or(DEFAULT_PLACES_LIMIT)
.min(MAX_PLACES_LIMIT);
let limit = PLACES_LIMIT;
let mode_filter = params.mode;
let places = tokio::task::spawn_blocking(move || {

View file

@ -8,7 +8,7 @@ use serde::Deserialize;
use tracing::{info, warn};
use crate::auth::OptionalUser;
use crate::consts::{DEFAULT_PROPERTIES_LIMIT, POSTCODE_SEARCH_OFFSET};
use crate::consts::{POSTCODE_SEARCH_OFFSET, PROPERTIES_LIMIT};
use crate::licensing::{check_license_point, resolve_share_code};
use crate::parsing::{parse_filters_with_poi, row_passes_filters, row_passes_poi_filters};
use crate::state::SharedState;
@ -24,7 +24,6 @@ pub struct PostcodePropertiesParams {
/// Pipe-separated travel time entries: `mode:slug|mode:slug:min:max`.
/// Optional min:max applies as a filter (exclude properties outside range).
pub travel: Option<String>,
pub limit: Option<usize>,
pub offset: Option<usize>,
/// Exact address to rank first when opening properties from address search.
pub focus_address: Option<String>,
@ -151,7 +150,7 @@ pub async fn get_postcode_properties(
});
let total = matching_rows.len();
let limit = params.limit.unwrap_or(DEFAULT_PROPERTIES_LIMIT);
let limit = PROPERTIES_LIMIT;
let page_offset = params.offset.unwrap_or(0);
let truncated = total > page_offset + limit;
@ -186,7 +185,6 @@ pub async fn get_postcode_properties(
Ok(PropertyListResponse {
properties,
total,
limit,
offset: page_offset,
truncated,
})

View file

@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize};
use tracing::{info, warn};
use crate::auth::OptionalUser;
use crate::consts::DEFAULT_PROPERTIES_LIMIT;
use crate::consts::PROPERTIES_LIMIT;
use crate::data::RenovationEvent;
use crate::licensing::{check_license_bounds, resolve_share_code};
use crate::parsing::{
@ -29,7 +29,6 @@ pub struct HexagonPropertiesParams {
/// Pipe-separated travel time entries: `mode:slug|mode:slug:min:max`.
/// Optional min:max applies as a filter (exclude properties outside range).
pub travel: Option<String>,
pub limit: Option<usize>,
pub offset: Option<usize>,
/// Share-link code; grants bbox-scoped access for unlicensed users.
pub share: Option<String>,
@ -69,7 +68,6 @@ pub struct Property {
pub struct PropertyListResponse {
pub properties: Vec<Property>,
pub total: usize,
pub limit: usize,
pub offset: usize,
pub truncated: bool,
}
@ -276,7 +274,7 @@ pub async fn get_hexagon_properties(
matching_rows.sort_unstable_by_key(|&row| state.data.address(row).trim().is_empty());
let total = matching_rows.len();
let limit = params.limit.unwrap_or(DEFAULT_PROPERTIES_LIMIT);
let limit = PROPERTIES_LIMIT;
let offset = params.offset.unwrap_or(0);
let truncated = total > offset + limit;
@ -312,7 +310,6 @@ pub async fn get_hexagon_properties(
Ok(PropertyListResponse {
properties,
total,
limit,
offset,
truncated,
})

View file

@ -4,7 +4,7 @@ use metrics::counter;
use rustc_hash::FxHashMap;
use tracing::error;
use crate::consts::MAX_PRICE_HISTORY_POINTS;
use crate::consts::PRICE_HISTORY_POINTS_LIMIT;
use crate::data::{FeatureStats, PostcodePoiMetrics, PropertyData};
use super::hexagon_stats::{EnumFeatureStats, HistogramStats, NumericFeatureStats, PricePoint};
@ -32,9 +32,9 @@ pub fn extract_price_history(
}
})
.collect();
if points.len() > MAX_PRICE_HISTORY_POINTS {
let step = points.len() as f64 / MAX_PRICE_HISTORY_POINTS as f64;
points = (0..MAX_PRICE_HISTORY_POINTS)
if points.len() > PRICE_HISTORY_POINTS_LIMIT {
let step = points.len() as f64 / PRICE_HISTORY_POINTS_LIMIT as f64;
points = (0..PRICE_HISTORY_POINTS_LIMIT)
.map(|i| {
let idx = (i as f64 * step) as usize;
PricePoint {