Skip to content

Commit 15c49ef

Browse files
authored
chore: bump msrv version (#944)
Getting to dive into DuckDB query performance!
1 parent 3e46367 commit 15c49ef

11 files changed

Lines changed: 124 additions & 133 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ homepage = "https://stac-utils.github.io/rustac"
3030
repository = "https://github.com/stac-utils/rustac"
3131
license = "MIT OR Apache-2.0"
3232
categories = ["science", "data-structures"]
33-
rust-version = "1.85"
33+
rust-version = "1.88"
3434

3535
[workspace.dependencies]
3636
anyhow = "1.0"

crates/cli/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ impl Rustac {
458458
load_collection_items,
459459
create_collections,
460460
} => {
461-
let bind = bind.as_deref().unwrap_or(&addr);
461+
let bind = bind.as_deref().unwrap_or(addr);
462462
if matches!(use_duckdb, Some(true))
463463
|| (use_duckdb.is_none() && hrefs.len() == 1 && hrefs[0].ends_with("parquet"))
464464
{

crates/core/src/api/items.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,10 @@ impl Items {
114114
/// let items = Items::default().valid().unwrap();
115115
/// ```
116116
pub fn valid(self) -> Result<Items> {
117-
if let Some(bbox) = self.bbox.as_ref() {
118-
if !bbox.is_valid() {
119-
return Err(Error::InvalidBbox((*bbox).into(), "invalid bbox"));
120-
}
117+
if let Some(bbox) = self.bbox.as_ref()
118+
&& !bbox.is_valid()
119+
{
120+
return Err(Error::InvalidBbox((*bbox).into(), "invalid bbox"));
121121
}
122122
if let Some(datetime) = self.datetime.as_deref() {
123123
if let Some((start, end)) = datetime.split_once('/') {
@@ -126,10 +126,10 @@ impl Items {
126126
maybe_parse_from_rfc3339(end)?,
127127
);
128128
if let Some(start) = start {
129-
if let Some(end) = end {
130-
if end < start {
131-
return Err(Error::StartIsAfterEnd(start, end));
132-
}
129+
if let Some(end) = end
130+
&& end < start
131+
{
132+
return Err(Error::StartIsAfterEnd(start, end));
133133
}
134134
} else if end.is_none() {
135135
return Err(Error::EmptyDatetimeInterval);
@@ -186,7 +186,7 @@ impl Items {
186186
#[cfg(feature = "geo")]
187187
{
188188
let bbox: geo::Rect = (*bbox).into();
189-
item.intersects(&bbox).map_err(Error::from)
189+
item.intersects(&bbox)
190190
}
191191
#[cfg(not(feature = "geo"))]
192192
{
@@ -215,7 +215,7 @@ impl Items {
215215
/// ```
216216
pub fn datetime_matches(&self, item: &Item) -> Result<bool> {
217217
if let Some(datetime) = self.datetime.as_ref() {
218-
item.intersects_datetime_str(datetime).map_err(Error::from)
218+
item.intersects_datetime_str(datetime)
219219
} else {
220220
Ok(true)
221221
}

crates/core/src/api/search.rs

Lines changed: 41 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ impl Search {
239239
#[cfg(feature = "geo")]
240240
{
241241
let intersects: geo::Geometry = intersects.try_into().map_err(Box::new)?;
242-
item.intersects(&intersects).map_err(Error::from)
242+
item.intersects(&intersects)
243243
}
244244
#[cfg(not(feature = "geo"))]
245245
{
@@ -363,26 +363,25 @@ fn expand_datetime_to_start(s: &str) -> Result<DateTime<FixedOffset>> {
363363
let midnight = NaiveTime::from_hms_opt(0, 0, 0).expect("midnight (0, 0, 0) is always valid");
364364

365365
// Case 1: Year only (e.g., "2023") -> 2023-01-01T00:00:00Z
366-
if trimmed.len() == 4 && trimmed.chars().all(|c| c.is_numeric()) {
367-
if let Ok(year) = trimmed.parse::<i32>() {
368-
let date = NaiveDate::from_ymd_opt(year, 1, 1).ok_or(Error::InvalidYear(year))?;
369-
let datetime = date.and_time(midnight);
370-
return Ok(Utc.from_utc_datetime(&datetime).fixed_offset());
371-
}
366+
if trimmed.len() == 4
367+
&& trimmed.chars().all(|c| c.is_numeric())
368+
&& let Ok(year) = trimmed.parse::<i32>()
369+
{
370+
let date = NaiveDate::from_ymd_opt(year, 1, 1).ok_or(Error::InvalidYear(year))?;
371+
let datetime = date.and_time(midnight);
372+
return Ok(Utc.from_utc_datetime(&datetime).fixed_offset());
372373
}
373374

374375
// Case 2: Year-Month (e.g., "2023-01") -> 2023-01-01T00:00:00Z
375-
if trimmed.len() == 7 && trimmed.chars().nth(4) == Some('-') {
376-
if let Some((year_str, month_str)) = trimmed.split_once('-') {
377-
if let (Ok(year), Ok(month)) = (year_str.parse::<i32>(), month_str.parse::<u32>()) {
378-
if (1..=12).contains(&month) {
379-
let date =
380-
NaiveDate::from_ymd_opt(year, month, 1).ok_or(Error::InvalidYear(year))?;
381-
let datetime = date.and_time(midnight);
382-
return Ok(Utc.from_utc_datetime(&datetime).fixed_offset());
383-
}
384-
}
385-
}
376+
if trimmed.len() == 7
377+
&& trimmed.chars().nth(4) == Some('-')
378+
&& let Some((year_str, month_str)) = trimmed.split_once('-')
379+
&& let (Ok(year), Ok(month)) = (year_str.parse::<i32>(), month_str.parse::<u32>())
380+
&& (1..=12).contains(&month)
381+
{
382+
let date = NaiveDate::from_ymd_opt(year, month, 1).ok_or(Error::InvalidYear(year))?;
383+
let datetime = date.and_time(midnight);
384+
return Ok(Utc.from_utc_datetime(&datetime).fixed_offset());
386385
}
387386

388387
// Case 3: ISO 8601 date (e.g., "2023-06-15") -> 2023-06-15T00:00:00Z
@@ -400,34 +399,34 @@ fn expand_datetime_to_end(s: &str) -> Result<DateTime<FixedOffset>> {
400399
let end_of_day = NaiveTime::from_hms_opt(23, 59, 59).expect("23:59:59 is always valid");
401400

402401
// Case 1: Year only (e.g., "2023") -> 2023-12-31T23:59:59Z
403-
if trimmed.len() == 4 && trimmed.chars().all(|c| c.is_numeric()) {
404-
if let Ok(year) = trimmed.parse::<i32>() {
405-
let date = NaiveDate::from_ymd_opt(year, 12, 31).ok_or(Error::InvalidYear(year))?;
406-
let datetime = date.and_time(end_of_day);
407-
return Ok(Utc.from_utc_datetime(&datetime).fixed_offset());
408-
}
402+
if trimmed.len() == 4
403+
&& trimmed.chars().all(|c| c.is_numeric())
404+
&& let Ok(year) = trimmed.parse::<i32>()
405+
{
406+
let date = NaiveDate::from_ymd_opt(year, 12, 31).ok_or(Error::InvalidYear(year))?;
407+
let datetime = date.and_time(end_of_day);
408+
return Ok(Utc.from_utc_datetime(&datetime).fixed_offset());
409409
}
410410

411411
// Case 2: Year-Month (e.g., "2023-01") -> 2023-01-31T23:59:59Z (last day of month)
412-
if trimmed.len() == 7 && trimmed.chars().nth(4) == Some('-') {
413-
if let Some((year_str, month_str)) = trimmed.split_once('-') {
414-
if let (Ok(year), Ok(month)) = (year_str.parse::<i32>(), month_str.parse::<u32>()) {
415-
if (1..=12).contains(&month) {
416-
// Get the last day of the month by going to first day of next month, then back one day
417-
let last_day = if month == 12 {
418-
NaiveDate::from_ymd_opt(year + 1, 1, 1)
419-
} else {
420-
NaiveDate::from_ymd_opt(year, month + 1, 1)
421-
}
422-
.ok_or(Error::InvalidYear(year))?
423-
.pred_opt()
424-
.ok_or(Error::InvalidYear(year))?;
425-
426-
let datetime = last_day.and_time(end_of_day);
427-
return Ok(Utc.from_utc_datetime(&datetime).fixed_offset());
428-
}
429-
}
412+
if trimmed.len() == 7
413+
&& trimmed.chars().nth(4) == Some('-')
414+
&& let Some((year_str, month_str)) = trimmed.split_once('-')
415+
&& let (Ok(year), Ok(month)) = (year_str.parse::<i32>(), month_str.parse::<u32>())
416+
&& (1..=12).contains(&month)
417+
{
418+
// Get the last day of the month by going to first day of next month, then back one day
419+
let last_day = if month == 12 {
420+
NaiveDate::from_ymd_opt(year + 1, 1, 1)
421+
} else {
422+
NaiveDate::from_ymd_opt(year, month + 1, 1)
430423
}
424+
.ok_or(Error::InvalidYear(year))?
425+
.pred_opt()
426+
.ok_or(Error::InvalidYear(year))?;
427+
428+
let datetime = last_day.and_time(end_of_day);
429+
return Ok(Utc.from_utc_datetime(&datetime).fixed_offset());
431430
}
432431

433432
// Case 3: ISO 8601 date (e.g., "2023-06-15") -> 2023-06-15T23:59:59Z

crates/core/src/collection.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -360,15 +360,15 @@ impl TemporalExtent {
360360
if self.interval.is_empty() {
361361
self.interval.push([start, end]);
362362
} else {
363-
if let Some(start) = start {
364-
if self.interval[0][0].map(|dt| dt > start).unwrap_or(true) {
365-
self.interval[0][0] = Some(start);
366-
}
363+
if let Some(start) = start
364+
&& self.interval[0][0].map(|dt| dt > start).unwrap_or(true)
365+
{
366+
self.interval[0][0] = Some(start);
367367
}
368-
if let Some(end) = end {
369-
if self.interval[0][1].map(|dt| dt < end).unwrap_or(true) {
370-
self.interval[0][1] = Some(end);
371-
}
368+
if let Some(end) = end
369+
&& self.interval[0][1].map(|dt| dt < end).unwrap_or(true)
370+
{
371+
self.interval[0][1] = Some(end);
372372
}
373373
}
374374
}

crates/core/src/geoparquet.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -456,12 +456,13 @@ impl WriterState {
456456
/// assert_eq!(metadata[1].key, "stac-geoparquet");
457457
/// ```
458458
pub fn into_metadata(self) -> Result<Vec<KeyValue>> {
459-
let mut metadata = Vec::with_capacity(2);
460-
metadata.push(self.encoder.into_keyvalue()?);
461-
metadata.push(KeyValue::new(
462-
METADATA_KEY.to_string(),
463-
serde_json::to_string(&self.metadata)?,
464-
));
459+
let metadata = vec![
460+
self.encoder.into_keyvalue()?,
461+
KeyValue::new(
462+
METADATA_KEY.to_string(),
463+
serde_json::to_string(&self.metadata)?,
464+
),
465+
];
465466
Ok(metadata)
466467
}
467468
}

crates/core/src/item.rs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -528,19 +528,17 @@ impl Item {
528528
) -> Result<bool> {
529529
let (item_start, item_end) = self.datetimes();
530530
let mut intersects = true;
531-
if let Some(start) = start {
532-
if let Some(item_end) = item_end {
533-
if item_end < start {
534-
intersects = false;
535-
}
536-
}
531+
if let Some(start) = start
532+
&& let Some(item_end) = item_end
533+
&& item_end < start
534+
{
535+
intersects = false;
537536
}
538-
if let Some(end) = end {
539-
if let Some(item_start) = item_start {
540-
if item_start > end {
541-
intersects = false;
542-
}
543-
}
537+
if let Some(end) = end
538+
&& let Some(item_start) = item_start
539+
&& item_start > end
540+
{
541+
intersects = false;
544542
}
545543
Ok(intersects)
546544
}

crates/core/src/migrate.rs

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -166,17 +166,17 @@ fn migrate_bands(asset: &mut Map<String, Value>) -> Result<()> {
166166
}
167167
}
168168
for (key, count) in counts {
169-
if let Some((value_as_string, &count)) = count.iter().max_by_key(|&(_, &count)| count) {
170-
if count > 1 {
171-
let value = values
172-
.get(value_as_string)
173-
.expect("every value should be in the lookup hash")
174-
.clone();
175-
for band in &mut bands {
176-
if band.get(&key).map(|v| v == &value).unwrap_or_default() {
177-
let value = band.remove(&key).unwrap();
178-
let _ = asset.insert(key.clone(), value);
179-
}
169+
if let Some((value_as_string, &count)) = count.iter().max_by_key(|&(_, &count)| count)
170+
&& count > 1
171+
{
172+
let value = values
173+
.get(value_as_string)
174+
.expect("every value should be in the lookup hash")
175+
.clone();
176+
for band in &mut bands {
177+
if band.get(&key).map(|v| v == &value).unwrap_or_default() {
178+
let value = band.remove(&key).unwrap();
179+
let _ = asset.insert(key.clone(), value);
180180
}
181181
}
182182
}
@@ -193,20 +193,16 @@ fn migrate_bands(asset: &mut Map<String, Value>) -> Result<()> {
193193
fn migrate_links(object: &mut Map<String, Value>) {
194194
if let Some(links) = object.get_mut("links").and_then(|v| v.as_array_mut()) {
195195
for link in links {
196-
if let Some(link) = link.as_object_mut() {
197-
if link
196+
if let Some(link) = link.as_object_mut()
197+
&& link
198198
.get("rel")
199199
.and_then(|v| v.as_str())
200200
.map(|s| s == "self")
201201
.unwrap_or_default()
202-
{
203-
if let Some(href) = link.get("href").and_then(|v| v.as_str()) {
204-
if href.starts_with('/') {
205-
let _ =
206-
link.insert("href".to_string(), format!("file://{href}").into());
207-
}
208-
}
209-
}
202+
&& let Some(href) = link.get("href").and_then(|v| v.as_str())
203+
&& href.starts_with('/')
204+
{
205+
let _ = link.insert("href".to_string(), format!("file://{href}").into());
210206
}
211207
}
212208
}

crates/duckdb/src/client.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ impl Client {
234234
log::debug!("duckdb sql: {sql}");
235235
let mut statement = self.prepare(&sql)?;
236236
statement.execute(duckdb::params_from_iter(params))?;
237+
log::debug!("query complete");
237238
Ok(SearchArrowBatchIter::new(
238239
statement,
239240
self.convert_wkb,
@@ -284,12 +285,11 @@ impl Client {
284285
has_end_datetime = true;
285286
}
286287

287-
if let Some(fields) = search.fields.as_ref() {
288-
if fields.exclude.contains(&column)
289-
|| !(fields.include.is_empty() || fields.include.contains(&column))
290-
{
291-
continue;
292-
}
288+
if let Some(fields) = search.fields.as_ref()
289+
&& (fields.exclude.contains(&column)
290+
|| !(fields.include.is_empty() || fields.include.contains(&column)))
291+
{
292+
continue;
293293
}
294294

295295
if column == "geometry" {

crates/io/src/api.rs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ pub async fn search(
2525
max_items: Option<usize>,
2626
) -> Result<ItemCollection> {
2727
let client = Client::new(href)?;
28-
if search.limit.is_none() {
29-
if let Some(max_items) = max_items {
30-
search.limit = Some(max_items.try_into()?);
31-
}
28+
if search.limit.is_none()
29+
&& let Some(max_items) = max_items
30+
{
31+
search.limit = Some(max_items.try_into()?);
3232
}
3333
let stream = client.search(search).await?;
3434
let mut items = if let Some(max_items) = max_items {
@@ -43,10 +43,10 @@ pub async fn search(
4343
while let Some(item) = stream.next().await {
4444
let item = item?;
4545
items.push(item);
46-
if let Some(max_items) = max_items {
47-
if items.len() >= max_items {
48-
break;
49-
}
46+
if let Some(max_items) = max_items
47+
&& items.len() >= max_items
48+
{
49+
break;
5050
}
5151
}
5252
let item_collection = ItemCollection::new(items)?;
@@ -394,14 +394,13 @@ fn stream_pages(
394394

395395
fn not_found_to_none<T>(result: Result<T>) -> Result<Option<T>> {
396396
let mut result = result.map(Some);
397-
if let Err(Error::Reqwest(ref err)) = result {
398-
if err
397+
if let Err(Error::Reqwest(ref err)) = result
398+
&& err
399399
.status()
400400
.map(|s| s == StatusCode::NOT_FOUND)
401401
.unwrap_or_default()
402-
{
403-
result = Ok(None);
404-
}
402+
{
403+
result = Ok(None);
405404
}
406405
result
407406
}

0 commit comments

Comments
 (0)