-
Notifications
You must be signed in to change notification settings - Fork 26
Description
Is your feature request related to a problem? Please describe.
When using the Buffer API to insert rows, the fluent builder pattern is incredibly ergonomic. However, when working with real-world data structs that contain nullable fields (represented as Option<T> in Rust), developers are forced to break the method chain to use if let statements.
Because QuestDB treats missing columns as NULL, we have to conditionally call the column methods.
Example of the current pain point:
let mut buffer = Buffer::new(ProtocolVersion::V3);
// We must break the chain to handle optional values
let mut row = buffer.table("sensors")?
.symbol("location", "factory-1")?;
if let Some(temp) = sensor.temperature {
row.column_f64("temperature", temp)?;
}
if let Some(hum) = sensor.humidity {
row.column_f64("humidity", hum)?;
}
row.at_now()?;Describe the solution you'd like
I propose adding _opt variants for all column assignment methods directly to the Buffer struct (e.g., column_f64_opt, column_str_opt, symbol_opt, column_dec_opt, etc.).
If the provided value is Some(v), the method behaves exactly like its standard counterpart. If the value is None, it simply returns Ok(self) as a no-op, allowing the builder chain to continue unbroken.
The resulting developer experience:
let mut buffer = Buffer::new(ProtocolVersion::V3);
buffer
.table("sensors")?
.symbol("location", "factory-1")?
.column_f64_opt("temperature", sensor.temperature)? // Option<f64>
.column_f64_opt("humidity", sensor.humidity)? // Option<f64>
.at_now()?;Implementation Details
The new methods would reuse the exact same generic constraints currently used in the Buffer API (e.g., N: TryInto<ColumnName<'a>>) to ensure zero performance degradation and maintain compatibility with pre-validated names.
Example signature for strings:
pub fn column_str_opt<'a, N, S>(&mut self, name: N, value: Option<S>) -> crate::Result<&mut Self>
where
N: TryInto<ColumnName<'a>>,
S: AsRef<str>,
Error: From<N::Error>,
{
if let Some(v) = value {
self.column_str(name, v)
} else {
Ok(self)
}
}Additional context
I have already built this locally using a custom extension trait and it massively cleaned up my ingestion code. I think this would be highly beneficial for the broader community.
If the team is open to this API addition, I would be more than happy to open a PR adding these methods!