lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README | LICENSE

commit 42ee62c68a81efabeefac9b08ceaac0ced52fa56
parent d8941c1e8a5d8ef69dd8d893196c9eb24c3e2de9
Author: triesap <tyson@radroots.org>
Date:   Thu, 30 Apr 2026 06:32:33 +0000

replica: preserve listing discount notes

Diffstat:
Mcrates/replica_db/src/query.rs | 5+++--
Mcrates/replica_sync/src/ingest.rs | 46+++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 46 insertions(+), 5 deletions(-)

diff --git a/crates/replica_db/src/query.rs b/crates/replica_db/src/query.rs @@ -21,6 +21,7 @@ pub struct ReplicaTradeProductSummaryRow { pub price_qty_unit: String, pub listing_addr: Option<String>, pub primary_bin_id: Option<String>, + pub notes: Option<String>, pub location_primary: Option<String>, } @@ -39,7 +40,7 @@ impl<E: SqlExecutor> ReplicaSql<E> { &self, lookup: &str, ) -> Result<Vec<ReplicaTradeProductSummaryRow>, SqlError> { - let sql = "SELECT tp.id, tp.key, tp.category, tp.title, tp.summary, tp.qty_amt, tp.qty_unit, tp.qty_label, tp.qty_avail, tp.price_amt, tp.price_currency, tp.price_qty_amt, tp.price_qty_unit, tp.listing_addr, tp.primary_bin_id, loc.location_primary \ + let sql = "SELECT tp.id, tp.key, tp.category, tp.title, tp.summary, tp.qty_amt, tp.qty_unit, tp.qty_label, tp.qty_avail, tp.price_amt, tp.price_currency, tp.price_qty_amt, tp.price_qty_unit, tp.listing_addr, tp.primary_bin_id, tp.notes, loc.location_primary \ FROM trade_product tp \ LEFT JOIN (\ SELECT tpl.tb_tp AS trade_product_id, MIN(COALESCE(gl.label, gl.gc_name, gl.gc_admin1_name, gl.gc_country_name, gl.d_tag)) AS location_primary \ @@ -79,7 +80,7 @@ impl<E: SqlExecutor> ReplicaSql<E> { } let sql = format!( - "SELECT tp.id, tp.key, tp.category, tp.title, tp.summary, tp.qty_amt, tp.qty_unit, tp.qty_label, tp.qty_avail, tp.price_amt, tp.price_currency, tp.price_qty_amt, tp.price_qty_unit, tp.listing_addr, tp.primary_bin_id, loc.location_primary \ + "SELECT tp.id, tp.key, tp.category, tp.title, tp.summary, tp.qty_amt, tp.qty_unit, tp.qty_label, tp.qty_avail, tp.price_amt, tp.price_currency, tp.price_qty_amt, tp.price_qty_unit, tp.listing_addr, tp.primary_bin_id, tp.notes, loc.location_primary \ FROM trade_product tp \ LEFT JOIN (\ SELECT tpl.tb_tp AS trade_product_id, MIN(COALESCE(gl.label, gl.gc_name, gl.gc_admin1_name, gl.gc_country_name, gl.d_tag)) AS location_primary \ diff --git a/crates/replica_sync/src/ingest.rs b/crates/replica_sync/src/ingest.rs @@ -76,7 +76,7 @@ use radroots_replica_db_schema::trade_product::{ }; use radroots_sql_core::SqlExecutor; use radroots_sql_core::error::SqlError; -use serde_json::Value; +use serde_json::{Value, json}; use crate::error::RadrootsReplicaEventsError; use crate::event_state::{event_content_hash, event_state_key}; @@ -605,10 +605,29 @@ fn trade_product_fields_from_listing( price_qty_unit, listing_addr: Some(listing_addr.to_string()), primary_bin_id: Some(listing.primary_bin_id.clone()), - notes: None, + notes: trade_product_notes_from_listing(listing)?, }) } +fn trade_product_notes_from_listing( + listing: &RadrootsListing, +) -> Result<Option<String>, RadrootsReplicaEventsError> { + let Some(discounts) = listing + .discounts + .as_ref() + .filter(|discounts| !discounts.is_empty()) + else { + return Ok(None); + }; + serde_json::to_string(&json!({ "listing_discounts": discounts })) + .map(Some) + .map_err(|error| { + RadrootsReplicaEventsError::InvalidData(format!( + "listing discounts could not be serialized: {error}" + )) + }) +} + fn primary_listing_bin( listing: &RadrootsListing, ) -> Result<&RadrootsListingBin, RadrootsReplicaEventsError> { @@ -2291,7 +2310,7 @@ mod tests { let listing_d_tag = "AAAAAAAAAAAAAAAAAAAAAQ"; let listing_addr = format!("{}:{}:{}", KIND_LISTING, seller_pubkey, listing_d_tag); - let active = listing_event( + let mut active = listing_event( 500, &seller_pubkey, 10, @@ -2299,6 +2318,21 @@ mod tests { "active", "Pasture Eggs", ); + active.tags.push(vec![ + "radroots:discount".to_string(), + serde_json::json!({ + "scope": "bin", + "threshold": { + "kind": "bin_count", + "amount": { "bin_id": "bin-a", "min": 1 } + }, + "value": { + "kind": "percent", + "amount": { "value": "10" } + } + }) + .to_string(), + ]); assert_eq!( radroots_replica_ingest_event(&exec, &active).expect("active ingest"), RadrootsReplicaIngestOutcome::Applied @@ -2319,6 +2353,12 @@ mod tests { assert_eq!(search_rows[0].qty_avail, Some(5)); assert_eq!(search_rows[0].price_amt, 6.0); assert_eq!(search_rows[0].price_currency, "USD"); + assert!( + search_rows[0] + .notes + .as_deref() + .is_some_and(|notes| notes.contains("listing_discounts")) + ); let updated = listing_event( 501,