From 0ba909add8104f93012e1a5adff4bdd91564ad43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Tue, 29 Oct 2024 20:57:00 +0200 Subject: [PATCH] Take the field index, not name, in the feature getters and setters --- CHANGES.md | 6 + examples/read_write_ogr.rs | 6 +- examples/read_write_ogr_datetime.rs | 6 +- examples/write_ogr.rs | 72 ++----- src/vector/defn.rs | 21 +- src/vector/feature.rs | 295 +++++++++------------------- src/vector/layer.rs | 210 ++++++++++---------- src/vector/sql.rs | 12 +- 8 files changed, 250 insertions(+), 378 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 89f067d5..6f03a5a0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,11 @@ - Include OS-specific versions of the pre-built bindings ([#574](https://github.com/georust/gdal/pull/574)) - Upgrade `ndarray` dependency to 0.16 ([#569](https://github.com/georust/gdal/pull/569)) - Upgrade `thiserror` dependency to 2.0 ([#586](https://github.com/georust/gdal/pull/586)) + - Update `Feature::field`, `Feature::set_field`, `Feature::set_field_string`, `Feature::set_field_string_list`, `Feature::set_field_double`, `Feature::set_field_double_list`, `Feature::set_field_integer`, `Feature::set_field_integer_list`, `Feature::set_field_integer64`, `Feature::set_field_integer64_list`, `Feature::set_field_datetime`, `Feature::set_field_null`, `Feature::unset_field` to take a field index, not a name ([#581](https://github.com/georust/gdal/pull/581)) + - Drop `Feature::field_as_integer_by_name`, `Feature::field_as_integer64_by_name`, `Feature::field_as_double_by_name`, `Feature::field_as_string_by_name`, `Feature::field_as_datetime_by_name` ([#581](https://github.com/georust/gdal/pull/581)) + - Update `Feature::field_count` to return `usize` instead of `i32` ([#581](https://github.com/georust/gdal/pull/581)) + - Update `Feature::field_as_integer`, `Feature::field_as_integer64`, `Feature::field_as_double`, `Feature::field_as_string`, `Feature::field_as_datetime` to take the field index as `usize` instead of `i32` ([#581](https://github.com/georust/gdal/pull/581)) + - Drop `LayerAccess::create_feature_fields` ([#581](https://github.com/georust/gdal/pull/581)) ### Added @@ -17,6 +22,7 @@ - Add pre-built bindings for GDAL 3.10 ([#573](https://github.com/georust/gdal/pull/573)) - Add methods `alternative_name`, `is_nullable`, `is_unique`, `default_value` to `Field` ([#561](https://github.com/georust/gdal/pull/561)) - Add `Defn::geometry_type` ([#562](https://github.com/georust/gdal/pull/562)) + - Add `Defn::field_index` and `Feature::field_index` ([#581](https://github.com/georust/gdal/pull/581)) ### Fixed diff --git a/examples/read_write_ogr.rs b/examples/read_write_ogr.rs index 6c45946f..ee59f485 100644 --- a/examples/read_write_ogr.rs +++ b/examples/read_write_ogr.rs @@ -52,9 +52,9 @@ fn run() -> Result<()> { } // copy each field value of the feature: - for fd in &fields_defn { - if let Some(value) = feature_a.field(&fd.0)? { - ft.set_field(&fd.0, &value)?; + for idx in 0..fields_defn.len() { + if let Some(value) = feature_a.field(idx)? { + ft.set_field(idx, &value)?; } } // Add the feature to the layer: diff --git a/examples/read_write_ogr_datetime.rs b/examples/read_write_ogr_datetime.rs index 3e49e501..30beb6c5 100644 --- a/examples/read_write_ogr_datetime.rs +++ b/examples/read_write_ogr_datetime.rs @@ -35,10 +35,10 @@ fn run() -> gdal::errors::Result<()> { ft.set_geometry(geom.clone())?; } // copy each field value of the feature: - for field in defn.fields() { + for (idx, field) in defn.fields().enumerate() { ft.set_field( - &field.name(), - &match feature_a.field(field.name())?.unwrap() { + idx, + &match feature_a.field(idx)?.unwrap() { // add one day to dates FieldValue::DateValue(value) => { println!("{} = {}", field.name(), value); diff --git a/examples/write_ogr.rs b/examples/write_ogr.rs index 21cb6856..036debf3 100644 --- a/examples/write_ogr.rs +++ b/examples/write_ogr.rs @@ -1,10 +1,9 @@ use gdal::errors::Result; -use gdal::vector::{Defn, Feature, FieldDefn, FieldValue, Geometry, LayerAccess, OGRFieldType}; +use gdal::vector::{Defn, Feature, FieldDefn, Geometry, OGRFieldType}; use gdal::DriverManager; use std::fs; -/// Example 1, the detailed way: -fn example_1() -> Result<()> { +fn main() -> Result<()> { let path = std::env::temp_dir().join("output1.geojson"); let _ = fs::remove_file(&path); let drv = DriverManager::get_driver_by_name("GeoJSON")?; @@ -21,25 +20,28 @@ fn example_1() -> Result<()> { let defn = Defn::from_layer(&lyr); + let name_idx = defn.field_index("Name")?; + let value_idx = defn.field_index("Value")?; + // 1st feature: let mut ft = Feature::new(&defn)?; ft.set_geometry(Geometry::from_wkt("POINT (45.21 21.76)")?)?; - ft.set_field_string("Name", "Feature 1")?; - ft.set_field_double("Value", 45.78)?; + ft.set_field_string(name_idx, "Feature 1")?; + ft.set_field_double(value_idx, 45.78)?; ft.create(&lyr)?; // 2nd feature: let mut ft = Feature::new(&defn)?; - ft.set_field_double("Value", 0.789)?; + ft.set_field_double(value_idx, 0.789)?; ft.set_geometry(Geometry::from_wkt("POINT (46.50 22.50)")?)?; - ft.set_field_string("Name", "Feature 2")?; + ft.set_field_string(name_idx, "Feature 2")?; ft.create(&lyr)?; // Feature triggering an error due to a wrong field name: let mut ft = Feature::new(&defn)?; ft.set_geometry(Geometry::from_wkt("POINT (46.50 22.50)")?)?; - ft.set_field_string("Name", "Feature 2")?; - match ft.set_field_double("Values", 0.789) { + ft.set_field_string(name_idx, "Feature 2")?; + match ft.set_field_double(value_idx, 0.789) { Ok(v) => v, Err(err) => println!("{err}"), }; @@ -47,55 +49,3 @@ fn example_1() -> Result<()> { Ok(()) } - -/// Example 2, same output, shortened way: -fn example_2() -> Result<()> { - let path = std::env::temp_dir().join("output2.geojson"); - let _ = fs::remove_file(&path); - let driver = DriverManager::get_driver_by_name("GeoJSON")?; - let mut ds = driver.create_vector_only(path.to_str().unwrap())?; - let mut layer = ds.create_layer(Default::default())?; - - layer.create_defn_fields(&[ - ("Name", OGRFieldType::OFTString), - ("Value", OGRFieldType::OFTReal), - ])?; - - layer.create_feature_fields( - Geometry::from_wkt("POINT (45.21 21.76)")?, - &["Name", "Value"], - &[ - FieldValue::StringValue("Feature 1".to_string()), - FieldValue::RealValue(45.78), - ], - )?; - - layer.create_feature_fields( - Geometry::from_wkt("POINT (46.50 22.50)")?, - &["Name", "Value"], - &[ - FieldValue::StringValue("Feature 2".to_string()), - FieldValue::RealValue(0.789), - ], - )?; - - // Feature creation triggering an error due to a wrong field name: - match layer.create_feature_fields( - Geometry::from_wkt("POINT (46.50 22.50)")?, - &["Abcd", "Value"], - &[ - FieldValue::StringValue("Feature 2".to_string()), - FieldValue::RealValue(0.789), - ], - ) { - Ok(v) => v, - Err(err) => println!("{err}"), - }; - - Ok(()) -} - -fn main() { - example_1().unwrap(); - example_2().unwrap(); -} diff --git a/src/vector/defn.rs b/src/vector/defn.rs index 8797d857..a4f08db4 100644 --- a/src/vector/defn.rs +++ b/src/vector/defn.rs @@ -1,4 +1,4 @@ -use std::ffi::c_int; +use std::ffi::{c_int, CString}; use gdal_sys::{ OGRFeatureDefnH, OGRFieldDefnH, OGRFieldType, OGRGeomFieldDefnH, OGRwkbGeometryType, @@ -66,6 +66,25 @@ impl Defn { pub fn geometry_type(&self) -> OGRwkbGeometryType::Type { unsafe { gdal_sys::OGR_FD_GetGeomType(self.c_defn) } } + + /// Get the index of a field. + /// + /// If the field is missing, returns [`GdalError::InvalidFieldName`]. + /// + pub fn field_index>(&self, field_name: S) -> Result { + let c_str_field_name = CString::new(field_name.as_ref())?; + let field_id = + unsafe { gdal_sys::OGR_FD_GetFieldIndex(self.c_defn(), c_str_field_name.as_ptr()) }; + if field_id == -1 { + return Err(GdalError::InvalidFieldName { + field_name: field_name.as_ref().to_string(), + method_name: "OGR_FD_GetFieldIndex", + }); + } + + let idx = field_id.try_into()?; + Ok(idx) + } } pub struct FieldIterator<'a> { diff --git a/src/vector/feature.rs b/src/vector/feature.rs index 491a8446..331cb198 100644 --- a/src/vector/feature.rs +++ b/src/vector/feature.rs @@ -72,88 +72,80 @@ impl<'a> Feature<'a> { } } - /// Get the value of a named field. If the field exists, it returns a [`FieldValue`] wrapper, - /// that you need to unpack to a base type (string, float, etc). - /// - /// If the field is missing, returns [`GdalError::InvalidFieldName`]. - /// - /// If the field has an unsupported type, returns a [`GdalError::UnhandledFieldType`]. - /// - /// If the field is null, returns `None`. - pub fn field>(&self, name: S) -> Result> { - let idx = self.field_idx_from_name(name)?; - self.field_from_id(idx) - } - - /// Get the value of a named field. If the field exists, it returns a [`FieldValue`] wrapper, + /// Get the value of a field. If the field exists, it returns a [`FieldValue`] wrapper, /// that you need to unpack to a base type (string, float, etc). /// /// If the field has an unhandled type, returns a [`GdalError::UnhandledFieldType`]. /// /// If the field is null, returns `None`. - fn field_from_id(&self, field_id: i32) -> Result> { - if unsafe { gdal_sys::OGR_F_IsFieldNull(self.c_feature, field_id) } != 0 { + pub fn field(&self, field_idx: usize) -> Result> { + let field_idx = field_idx.try_into()?; + + if unsafe { gdal_sys::OGR_F_IsFieldNull(self.c_feature, field_idx) } != 0 { return Ok(None); } - let field_defn = unsafe { gdal_sys::OGR_F_GetFieldDefnRef(self.c_feature, field_id) }; + let field_defn = unsafe { gdal_sys::OGR_F_GetFieldDefnRef(self.c_feature, field_idx) }; let field_type = unsafe { gdal_sys::OGR_Fld_GetType(field_defn) }; match field_type { OGRFieldType::OFTString => { - let rv = unsafe { gdal_sys::OGR_F_GetFieldAsString(self.c_feature, field_id) }; + let rv = unsafe { gdal_sys::OGR_F_GetFieldAsString(self.c_feature, field_idx) }; Ok(Some(FieldValue::StringValue(_string(rv)))) } OGRFieldType::OFTStringList => { let rv = unsafe { - let ptr = gdal_sys::OGR_F_GetFieldAsStringList(self.c_feature, field_id); + let ptr = gdal_sys::OGR_F_GetFieldAsStringList(self.c_feature, field_idx); _string_array(ptr) }; Ok(Some(FieldValue::StringListValue(rv))) } OGRFieldType::OFTReal => { - let rv = unsafe { gdal_sys::OGR_F_GetFieldAsDouble(self.c_feature, field_id) }; + let rv = unsafe { gdal_sys::OGR_F_GetFieldAsDouble(self.c_feature, field_idx) }; Ok(Some(FieldValue::RealValue(rv))) } OGRFieldType::OFTRealList => { let rv = unsafe { let mut len: i32 = 0; let ptr = - gdal_sys::OGR_F_GetFieldAsDoubleList(self.c_feature, field_id, &mut len); + gdal_sys::OGR_F_GetFieldAsDoubleList(self.c_feature, field_idx, &mut len); slice::from_raw_parts(ptr, len as usize).to_vec() }; Ok(Some(FieldValue::RealListValue(rv))) } OGRFieldType::OFTInteger => { - let rv = unsafe { gdal_sys::OGR_F_GetFieldAsInteger(self.c_feature, field_id) }; + let rv = unsafe { gdal_sys::OGR_F_GetFieldAsInteger(self.c_feature, field_idx) }; Ok(Some(FieldValue::IntegerValue(rv))) } OGRFieldType::OFTIntegerList => { let rv = unsafe { let mut len: i32 = 0; let ptr = - gdal_sys::OGR_F_GetFieldAsIntegerList(self.c_feature, field_id, &mut len); + gdal_sys::OGR_F_GetFieldAsIntegerList(self.c_feature, field_idx, &mut len); slice::from_raw_parts(ptr, len as usize).to_vec() }; Ok(Some(FieldValue::IntegerListValue(rv))) } OGRFieldType::OFTInteger64 => { - let rv = unsafe { gdal_sys::OGR_F_GetFieldAsInteger64(self.c_feature, field_id) }; + let rv = unsafe { gdal_sys::OGR_F_GetFieldAsInteger64(self.c_feature, field_idx) }; Ok(Some(FieldValue::Integer64Value(rv))) } OGRFieldType::OFTInteger64List => { let rv = unsafe { let mut len: i32 = 0; - let ptr = - gdal_sys::OGR_F_GetFieldAsInteger64List(self.c_feature, field_id, &mut len); + let ptr = gdal_sys::OGR_F_GetFieldAsInteger64List( + self.c_feature, + field_idx, + &mut len, + ); slice::from_raw_parts(ptr, len as usize).to_vec() }; Ok(Some(FieldValue::Integer64ListValue(rv))) } OGRFieldType::OFTDateTime => Ok(Some(FieldValue::DateTimeValue( - self._field_as_datetime(field_id)?, + self._field_as_datetime(field_idx)?, ))), OGRFieldType::OFTDate => Ok(Some(FieldValue::DateValue( - self._field_as_datetime(field_id)?.date_naive(), + self._field_as_datetime(field_idx)?.date_naive(), ))), _ => Err(GdalError::UnhandledFieldType { field_type, @@ -162,22 +154,23 @@ impl<'a> Feature<'a> { } } - /// Get the index of the named field. + /// Get the index of a field. /// /// If the field is missing, returns [`GdalError::InvalidFieldName`]. /// - fn field_idx_from_name>(&self, field_name: S) -> Result { + pub fn field_index>(&self, field_name: S) -> Result { let c_str_field_name = CString::new(field_name.as_ref())?; - let field_id = - unsafe { gdal_sys::OGR_F_GetFieldIndex(self.c_feature, c_str_field_name.as_ptr()) }; - if field_id == -1 { + let field_idx = + unsafe { gdal_sys::OGR_F_GetFieldIndex(self.c_feature(), c_str_field_name.as_ptr()) }; + if field_idx == -1 { return Err(GdalError::InvalidFieldName { field_name: field_name.as_ref().to_string(), method_name: "OGR_F_GetFieldIndex", }); } - Ok(field_id) + let field_index = field_idx.try_into()?; + Ok(field_index) } /// Get the value of the specified field as a [`i32`]. @@ -187,57 +180,20 @@ impl<'a> Feature<'a> { /// Returns `Ok(None)` if the field is null. /// Returns `Ok(Some(0))` on other kinds of errors. /// - pub fn field_as_integer(&self, field_idx: i32) -> Result> { + pub fn field_as_integer(&self, field_idx: usize) -> Result> { if field_idx >= self.field_count() { return Err(GdalError::InvalidFieldIndex { - index: field_idx as usize, + index: field_idx, method_name: "field_as_integer", }); } - if unsafe { gdal_sys::OGR_F_IsFieldNull(self.c_feature, field_idx) } != 0 { + let idx = field_idx.try_into()?; + if unsafe { gdal_sys::OGR_F_IsFieldNull(self.c_feature, idx) } != 0 { return Ok(None); } - let value = unsafe { gdal_sys::OGR_F_GetFieldAsInteger(self.c_feature, field_idx) }; - - Ok(Some(value)) - } - - /// Get the value of the specified field as a [`i32`]. - /// - /// If the field is missing, returns [`GdalError::InvalidFieldName`]. - /// - /// Returns `Ok(None)` if the field is null. - /// Returns `Ok(Some(0))` on other kinds of errors. - /// - pub fn field_as_integer_by_name(&self, field_name: &str) -> Result> { - let field_idx = self.field_idx_from_name(field_name)?; - - if unsafe { gdal_sys::OGR_F_IsFieldNull(self.c_feature, field_idx) } != 0 { - return Ok(None); - } - - let value = unsafe { gdal_sys::OGR_F_GetFieldAsInteger(self.c_feature, field_idx) }; - - Ok(Some(value)) - } - - /// Get the value of the specified field as a [`i64`]. - /// - /// If the field is missing, returns [`GdalError::InvalidFieldName`]. - /// - /// Returns `Ok(None)` if the field is null. - /// Returns `Ok(Some(0))` on other kinds of errors. - /// - pub fn field_as_integer64_by_name(&self, field_name: &str) -> Result> { - let field_idx = self.field_idx_from_name(field_name)?; - - if unsafe { gdal_sys::OGR_F_IsFieldNull(self.c_feature, field_idx) } != 0 { - return Ok(None); - } - - let value = unsafe { gdal_sys::OGR_F_GetFieldAsInteger64(self.c_feature, field_idx) }; + let value = unsafe { gdal_sys::OGR_F_GetFieldAsInteger(self.c_feature, idx) }; Ok(Some(value)) } @@ -249,38 +205,20 @@ impl<'a> Feature<'a> { /// Returns `Ok(None)` if the field is null. /// Returns `Ok(Some(0))` on other kinds of errors. /// - pub fn field_as_integer64(&self, field_idx: i32) -> Result> { + pub fn field_as_integer64(&self, field_idx: usize) -> Result> { if field_idx >= self.field_count() { return Err(GdalError::InvalidFieldIndex { - index: field_idx as usize, + index: field_idx, method_name: "field_as_integer64", }); } - if unsafe { gdal_sys::OGR_F_IsFieldNull(self.c_feature, field_idx) } != 0 { - return Ok(None); - } - - let value = unsafe { gdal_sys::OGR_F_GetFieldAsInteger64(self.c_feature, field_idx) }; - - Ok(Some(value)) - } - - /// Get the value of the specified field as a [`f64`]. - /// - /// If the field is missing, returns [`GdalError::InvalidFieldName`]. - /// - /// Returns `Ok(None)` if the field is null. - /// Returns `Ok(Some(0.))` on other kinds of errors. - /// - pub fn field_as_double_by_name(&self, field_name: &str) -> Result> { - let field_idx = self.field_idx_from_name(field_name)?; - - if unsafe { gdal_sys::OGR_F_IsFieldNull(self.c_feature, field_idx) } != 0 { + let idx = field_idx.try_into()?; + if unsafe { gdal_sys::OGR_F_IsFieldNull(self.c_feature, idx) } != 0 { return Ok(None); } - let value = unsafe { gdal_sys::OGR_F_GetFieldAsDouble(self.c_feature, field_idx) }; + let value = unsafe { gdal_sys::OGR_F_GetFieldAsInteger64(self.c_feature, idx) }; Ok(Some(value)) } @@ -292,37 +230,20 @@ impl<'a> Feature<'a> { /// Returns `Ok(None)` if the field is null. /// Returns `Ok(Some(0.))` on other kinds of errors. /// - pub fn field_as_double(&self, field_idx: i32) -> Result> { + pub fn field_as_double(&self, field_idx: usize) -> Result> { if field_idx >= self.field_count() { return Err(GdalError::InvalidFieldIndex { - index: field_idx as usize, + index: field_idx, method_name: "field_as_double", }); } - if unsafe { gdal_sys::OGR_F_IsFieldNull(self.c_feature, field_idx) } != 0 { + let idx = field_idx.try_into()?; + if unsafe { gdal_sys::OGR_F_IsFieldNull(self.c_feature, idx) } != 0 { return Ok(None); } - let value = unsafe { gdal_sys::OGR_F_GetFieldAsDouble(self.c_feature, field_idx) }; - - Ok(Some(value)) - } - - /// Get the value of the specified field as a [`String`]. - /// - /// If the field is missing, returns [`GdalError::InvalidFieldName`]. - /// - /// Returns `Ok(None)` if the field is null. - /// - pub fn field_as_string_by_name(&self, field_name: &str) -> Result> { - let field_idx = self.field_idx_from_name(field_name)?; - - if unsafe { gdal_sys::OGR_F_IsFieldNull(self.c_feature, field_idx) } != 0 { - return Ok(None); - } - - let value = _string(unsafe { gdal_sys::OGR_F_GetFieldAsString(self.c_feature, field_idx) }); + let value = unsafe { gdal_sys::OGR_F_GetFieldAsDouble(self.c_feature, idx) }; Ok(Some(value)) } @@ -333,40 +254,20 @@ impl<'a> Feature<'a> { /// /// Returns `Ok(None)` if the field is null. /// - pub fn field_as_string(&self, field_idx: i32) -> Result> { + pub fn field_as_string(&self, field_idx: usize) -> Result> { if field_idx >= self.field_count() { return Err(GdalError::InvalidFieldIndex { - index: field_idx as usize, + index: field_idx, method_name: "field_as_string", }); } - if unsafe { gdal_sys::OGR_F_IsFieldNull(self.c_feature, field_idx) } != 0 { - return Ok(None); - } - - let value = _string(unsafe { gdal_sys::OGR_F_GetFieldAsString(self.c_feature, field_idx) }); - - Ok(Some(value)) - } - - /// Get the value of the specified field as a [`DateTime`]. - /// - /// If the field is missing, returns [`GdalError::InvalidFieldName`]. - /// - /// Returns `Ok(None)` if the field is null. - /// - pub fn field_as_datetime_by_name( - &self, - field_name: &str, - ) -> Result>> { - let field_idx = self.field_idx_from_name(field_name)?; - - if unsafe { gdal_sys::OGR_F_IsFieldNull(self.c_feature, field_idx) } != 0 { + let idx = field_idx.try_into()?; + if unsafe { gdal_sys::OGR_F_IsFieldNull(self.c_feature, idx) } != 0 { return Ok(None); } - let value = self._field_as_datetime(field_idx)?; + let value = _string(unsafe { gdal_sys::OGR_F_GetFieldAsString(self.c_feature, idx) }); Ok(Some(value)) } @@ -377,19 +278,20 @@ impl<'a> Feature<'a> { /// /// Returns `Ok(None)` if the field is null. /// - pub fn field_as_datetime(&self, field_idx: i32) -> Result>> { + pub fn field_as_datetime(&self, field_idx: usize) -> Result>> { if field_idx >= self.field_count() { return Err(GdalError::InvalidFieldIndex { - index: field_idx as usize, + index: field_idx, method_name: "field_as_datetime", }); } - if unsafe { gdal_sys::OGR_F_IsFieldNull(self.c_feature, field_idx) } != 0 { + let idx = field_idx.try_into()?; + if unsafe { gdal_sys::OGR_F_IsFieldNull(self.c_feature, idx) } != 0 { return Ok(None); } - let value = self._field_as_datetime(field_idx)?; + let value = self._field_as_datetime(idx)?; Ok(Some(value)) } @@ -506,14 +408,15 @@ impl<'a> Feature<'a> { Ok(()) } - pub fn set_field_string(&mut self, field_name: &str, value: &str) -> Result<()> { + pub fn set_field_string(&mut self, field_idx: usize, value: &str) -> Result<()> { let c_str_value = CString::new(value)?; - let idx = self.field_idx_from_name(field_name)?; + let idx = field_idx.try_into()?; unsafe { gdal_sys::OGR_F_SetFieldString(self.c_feature, idx, c_str_value.as_ptr()) }; Ok(()) } - pub fn set_field_string_list(&mut self, field_name: &str, value: &[&str]) -> Result<()> { + pub fn set_field_string_list(&mut self, field_idx: usize, value: &[&str]) -> Result<()> { + let idx = field_idx.try_into()?; let c_strings = value .iter() .map(|&value| CString::new(value)) @@ -526,19 +429,18 @@ impl<'a> Feature<'a> { // OGR_F_SetFieldStringList takes a CSLConstList, which is defined as *mut *mut c_char in // gdal-sys despite being constant. let c_value = c_str_ptrs.as_ptr() as *mut *mut c_char; - let idx = self.field_idx_from_name(field_name)?; unsafe { gdal_sys::OGR_F_SetFieldStringList(self.c_feature, idx, c_value) }; Ok(()) } - pub fn set_field_double(&mut self, field_name: &str, value: f64) -> Result<()> { - let idx = self.field_idx_from_name(field_name)?; + pub fn set_field_double(&mut self, field_idx: usize, value: f64) -> Result<()> { + let idx = field_idx.try_into()?; unsafe { gdal_sys::OGR_F_SetFieldDouble(self.c_feature, idx, value as c_double) }; Ok(()) } - pub fn set_field_double_list(&mut self, field_name: &str, value: &[f64]) -> Result<()> { - let idx = self.field_idx_from_name(field_name)?; + pub fn set_field_double_list(&mut self, field_idx: usize, value: &[f64]) -> Result<()> { + let idx = field_idx.try_into()?; unsafe { gdal_sys::OGR_F_SetFieldDoubleList( self.c_feature, @@ -550,14 +452,14 @@ impl<'a> Feature<'a> { Ok(()) } - pub fn set_field_integer(&mut self, field_name: &str, value: i32) -> Result<()> { - let idx = self.field_idx_from_name(field_name)?; + pub fn set_field_integer(&mut self, field_idx: usize, value: i32) -> Result<()> { + let idx = field_idx.try_into()?; unsafe { gdal_sys::OGR_F_SetFieldInteger(self.c_feature, idx, value as c_int) }; Ok(()) } - pub fn set_field_integer_list(&mut self, field_name: &str, value: &[i32]) -> Result<()> { - let idx = self.field_idx_from_name(field_name)?; + pub fn set_field_integer_list(&mut self, field_idx: usize, value: &[i32]) -> Result<()> { + let idx = field_idx.try_into()?; unsafe { gdal_sys::OGR_F_SetFieldIntegerList( self.c_feature, @@ -569,14 +471,14 @@ impl<'a> Feature<'a> { Ok(()) } - pub fn set_field_integer64(&mut self, field_name: &str, value: i64) -> Result<()> { - let idx = self.field_idx_from_name(field_name)?; + pub fn set_field_integer64(&mut self, field_idx: usize, value: i64) -> Result<()> { + let idx = field_idx.try_into()?; unsafe { gdal_sys::OGR_F_SetFieldInteger64(self.c_feature, idx, value as c_longlong) }; Ok(()) } - pub fn set_field_integer64_list(&mut self, field_name: &str, value: &[i64]) -> Result<()> { - let idx = self.field_idx_from_name(field_name)?; + pub fn set_field_integer64_list(&mut self, field_idx: usize, value: &[i64]) -> Result<()> { + let idx = field_idx.try_into()?; unsafe { gdal_sys::OGR_F_SetFieldInteger64List( self.c_feature, @@ -590,11 +492,10 @@ impl<'a> Feature<'a> { pub fn set_field_datetime( &mut self, - field_name: &str, + field_idx: usize, value: DateTime, ) -> Result<()> { - let idx = self.field_idx_from_name(field_name)?; - + let idx = field_idx.try_into()?; let year = value.year() as c_int; let month = value.month() as c_int; let day = value.day() as c_int; @@ -623,21 +524,21 @@ impl<'a> Feature<'a> { Ok(()) } - pub fn set_field(&mut self, field_name: &str, value: &FieldValue) -> Result<()> { + pub fn set_field(&mut self, field_idx: usize, value: &FieldValue) -> Result<()> { match value { - FieldValue::IntegerValue(value) => self.set_field_integer(field_name, *value), - FieldValue::IntegerListValue(value) => self.set_field_integer_list(field_name, value), - FieldValue::Integer64Value(value) => self.set_field_integer64(field_name, *value), + FieldValue::IntegerValue(value) => self.set_field_integer(field_idx, *value), + FieldValue::IntegerListValue(value) => self.set_field_integer_list(field_idx, value), + FieldValue::Integer64Value(value) => self.set_field_integer64(field_idx, *value), FieldValue::Integer64ListValue(value) => { - self.set_field_integer64_list(field_name, value) + self.set_field_integer64_list(field_idx, value) } - FieldValue::StringValue(ref value) => self.set_field_string(field_name, value.as_str()), + FieldValue::StringValue(ref value) => self.set_field_string(field_idx, value.as_str()), FieldValue::StringListValue(ref value) => { let strs = value.iter().map(String::as_str).collect::>(); - self.set_field_string_list(field_name, &strs) + self.set_field_string_list(field_idx, &strs) } - FieldValue::RealValue(value) => self.set_field_double(field_name, *value), - FieldValue::RealListValue(value) => self.set_field_double_list(field_name, value), + FieldValue::RealValue(value) => self.set_field_double(field_idx, *value), + FieldValue::RealListValue(value) => self.set_field_double_list(field_idx, value), FieldValue::DateValue(value) => { let dv = value .and_hms_opt(0, 0, 0) @@ -647,9 +548,9 @@ impl<'a> Feature<'a> { FixedOffset::east_opt(0) .ok_or_else(|| GdalError::DateError("utc offset".into()))?, ); - self.set_field_datetime(field_name, dt) + self.set_field_datetime(field_idx, dt) } - FieldValue::DateTimeValue(value) => self.set_field_datetime(field_name, *value), + FieldValue::DateTimeValue(value) => self.set_field_datetime(field_idx, *value), } } @@ -658,8 +559,8 @@ impl<'a> Feature<'a> { /// See: [`OGRFeature::SetFieldNull`][SetFieldNull] /// /// [SetFieldNull]: https://gdal.org/api/ogrfeature_cpp.html#_CPPv4N10OGRFeature12SetFieldNullEi - pub fn set_field_null(&mut self, field_name: &str) -> Result<()> { - let idx = self.field_idx_from_name(field_name)?; + pub fn set_field_null(&mut self, field_idx: usize) -> Result<()> { + let idx = field_idx.try_into()?; unsafe { gdal_sys::OGR_F_SetFieldNull(self.c_feature(), idx) }; Ok(()) } @@ -669,8 +570,8 @@ impl<'a> Feature<'a> { /// See: [`OGRFeature::UnsetField`][UnsetField] /// /// [UnsetField]: https://gdal.org/api/ogrfeature_cpp.html#_CPPv4N10OGRFeature10UnsetFieldEi - pub fn unset_field(&mut self, field_name: &str) -> Result<()> { - let idx = self.field_idx_from_name(field_name)?; + pub fn unset_field(&mut self, field_idx: usize) -> Result<()> { + let idx = field_idx.try_into()?; unsafe { gdal_sys::OGR_F_UnsetField(self.c_feature(), idx) }; Ok(()) } @@ -687,8 +588,9 @@ impl<'a> Feature<'a> { Ok(()) } - pub fn field_count(&self) -> i32 { - unsafe { gdal_sys::OGR_F_GetFieldCount(self.c_feature) } + pub fn field_count(&self) -> usize { + let count = unsafe { gdal_sys::OGR_F_GetFieldCount(self.c_feature) }; + count as usize } pub fn fields(&self) -> FieldValueIterator { @@ -698,8 +600,8 @@ impl<'a> Feature<'a> { pub struct FieldValueIterator<'a> { feature: &'a Feature<'a>, - idx: i32, - count: i32, + idx: usize, + count: usize, } impl<'a> FieldValueIterator<'a> { @@ -721,12 +623,12 @@ impl<'a> Iterator for FieldValueIterator<'a> { if idx < self.count { self.idx += 1; let field_defn = - unsafe { gdal_sys::OGR_F_GetFieldDefnRef(self.feature.c_feature, idx) }; + unsafe { gdal_sys::OGR_F_GetFieldDefnRef(self.feature.c_feature, idx as c_int) }; let field_name = unsafe { gdal_sys::OGR_Fld_GetNameRef(field_defn) }; let name = _string(field_name); let fv: Option<(String, Option)> = self .feature - .field_from_id(idx) + .field(idx) .ok() .map(|field_value| (name, field_value)); //skip unknown types @@ -740,10 +642,7 @@ impl<'a> Iterator for FieldValueIterator<'a> { } fn size_hint(&self) -> (usize, Option) { - match Some(self.count).and_then(|s| s.try_into().ok()) { - Some(size) => (size, Some(size)), - None => (0, None), - } + (self.count, Some(self.count)) } } @@ -958,8 +857,9 @@ mod tests { let mut layer = ds.layers().next().expect("layer"); let mut feature = layer.features().next().expect("feature"); - feature.set_field_null("highway").unwrap(); - assert!(feature.field("highway").unwrap().is_none()); + let highway_idx = feature.field_index("highway").unwrap(); + feature.set_field_null(highway_idx).unwrap(); + assert!(feature.field(highway_idx).unwrap().is_none()); } #[test] @@ -968,6 +868,7 @@ mod tests { let mut layer = ds.layers().next().expect("layer"); let mut feature = layer.features().next().expect("feature"); - feature.unset_field("highway").unwrap(); + let highway_idx = feature.field_index("highway").unwrap(); + feature.unset_field(highway_idx).unwrap(); } } diff --git a/src/vector/layer.rs b/src/vector/layer.rs index fc63844c..4771e8c9 100644 --- a/src/vector/layer.rs +++ b/src/vector/layer.rs @@ -13,7 +13,7 @@ use crate::spatial_ref::SpatialRef; use crate::utils::{_last_null_pointer_err, _string}; use crate::vector::defn::Defn; use crate::vector::feature::{FeatureIterator, OwnedFeatureIterator}; -use crate::vector::{Envelope, Feature, FieldValue, Geometry, LayerOptions}; +use crate::vector::{Envelope, Feature, Geometry, LayerOptions}; use crate::{dataset::Dataset, gdal_major_object::MajorObject}; /// Layer capabilities @@ -321,21 +321,6 @@ pub trait LayerAccess: Sized { Ok(()) } - fn create_feature_fields( - &mut self, - geometry: Geometry, - field_names: &[&str], - values: &[FieldValue], - ) -> Result<()> { - let mut ft = Feature::new(self.defn())?; - ft.set_geometry(geometry)?; - for (fd, val) in field_names.iter().zip(values.iter()) { - ft.set_field(fd, val)?; - } - ft.create(self)?; - Ok(()) - } - /// Returns the number of features in this layer, even if it requires expensive calculation. /// /// Some drivers will actually scan the entire layer once to count objects. @@ -763,6 +748,7 @@ mod tests { use crate::spatial_ref::AxisMappingStrategy; use crate::test_utils::{fixture, open_gpkg_for_update, SuppressGDALErrorLog, TempFixture}; use crate::vector::feature::FeatureIterator; + use crate::vector::FieldValue; use crate::{assert_almost_eq, Dataset, DriverManager, GdalOpenFlags}; use gdal_sys::OGRwkbGeometryType; @@ -937,7 +923,8 @@ mod tests { { let feature = layer.features().next().unwrap(); - assert_eq!(feature.field("id").unwrap(), None); + let id_idx = feature.field_index("id").unwrap(); + assert_eq!(feature.field(id_idx).unwrap(), None); } // convert back to dataset @@ -971,16 +958,18 @@ mod tests { #[test] fn test_string_field() { with_feature("roads.geojson", 236194095, |feature| { + let highway_idx = feature.field_index("highway").unwrap(); assert_eq!( - feature.field("highway").unwrap().unwrap().into_string(), + feature.field(highway_idx).unwrap().unwrap().into_string(), Some("footway".to_string()) ); }); with_features("roads.geojson", |features| { assert_eq!( features - .filter(|field| { - let highway = field.field("highway").unwrap().unwrap().into_string(); + .filter(|feature| { + let highway_idx = feature.field_index("highway").unwrap(); + let highway = feature.field(highway_idx).unwrap().unwrap().into_string(); highway == Some("residential".to_string()) }) .count(), @@ -993,11 +982,13 @@ mod tests { fn test_null_field() { with_features("null_feature_fields.geojson", |mut features| { let feature = features.next().unwrap(); + let some_int_idx = feature.field_index("some_int").unwrap(); + let some_string_idx = feature.field_index("some_string").unwrap(); assert_eq!( - feature.field("some_int").unwrap(), + feature.field(some_int_idx).unwrap(), Some(FieldValue::IntegerValue(0)) ); - assert_eq!(feature.field("some_string").unwrap(), None); + assert_eq!(feature.field(some_string_idx).unwrap(), None); }); } @@ -1005,8 +996,9 @@ mod tests { fn test_string_list_field() { with_features("soundg.json", |mut features| { let feature = features.next().unwrap(); + let a_string_list_idx = feature.field_index("a_string_list").unwrap(); assert_eq!( - feature.field("a_string_list").unwrap().unwrap(), + feature.field(a_string_list_idx).unwrap().unwrap(), FieldValue::StringListValue(vec![ String::from("a"), String::from("list"), @@ -1021,13 +1013,14 @@ mod tests { fn test_set_string_list_field() { with_features("soundg.json", |mut features| { let mut feature = features.next().unwrap(); + let a_string_list_idx = feature.field_index("a_string_list").unwrap(); let value = FieldValue::StringListValue(vec![ String::from("the"), String::from("new"), String::from("strings"), ]); - feature.set_field("a_string_list", &value).unwrap(); - assert_eq!(feature.field("a_string_list").unwrap().unwrap(), value); + feature.set_field(a_string_list_idx, &value).unwrap(); + assert_eq!(feature.field(a_string_list_idx).unwrap().unwrap(), value); }); } @@ -1037,50 +1030,36 @@ mod tests { with_features("roads.geojson", |mut features| { let feature = features.next().unwrap(); + let sort_key_idx = feature.field_index("sort_key").unwrap(); + let highway_idx = feature.field_index("highway").unwrap(); + let railway_idx = feature.field_index("railway").unwrap(); + assert_eq!( - feature.field_as_string_by_name("highway").unwrap(), + feature.field_as_string(highway_idx).unwrap(), Some("footway".to_owned()) ); assert_eq!( - feature.field_as_string_by_name("sort_key").unwrap(), + feature.field_as_string(sort_key_idx).unwrap(), Some("-9".to_owned()) ); - assert_eq!( - feature.field_as_integer_by_name("sort_key").unwrap(), - Some(-9) - ); - assert_eq!( - feature.field_as_integer64_by_name("sort_key").unwrap(), - Some(-9) - ); - assert_eq!( - feature.field_as_double_by_name("sort_key").unwrap(), - Some(-9.) - ); + assert_eq!(feature.field_as_integer(sort_key_idx).unwrap(), Some(-9)); + assert_eq!(feature.field_as_integer64(sort_key_idx).unwrap(), Some(-9)); + assert_eq!(feature.field_as_double(sort_key_idx).unwrap(), Some(-9.)); // test failed conversions - assert_eq!( - feature.field_as_integer_by_name("highway").unwrap(), - Some(0) - ); - assert_eq!( - feature.field_as_integer64_by_name("highway").unwrap(), - Some(0) - ); - assert_eq!( - feature.field_as_double_by_name("highway").unwrap(), - Some(0.) - ); + assert_eq!(feature.field_as_integer(highway_idx).unwrap(), Some(0)); + assert_eq!(feature.field_as_integer64(highway_idx).unwrap(), Some(0)); + assert_eq!(feature.field_as_double(highway_idx).unwrap(), Some(0.)); // test nulls - assert_eq!(feature.field_as_string_by_name("railway").unwrap(), None); - assert_eq!(feature.field_as_integer_by_name("railway").unwrap(), None); - assert_eq!(feature.field_as_integer64_by_name("railway").unwrap(), None); - assert_eq!(feature.field_as_double_by_name("railway").unwrap(), None); + assert_eq!(feature.field_as_string(railway_idx).unwrap(), None); + assert_eq!(feature.field_as_integer(railway_idx).unwrap(), None); + assert_eq!(feature.field_as_integer64(railway_idx).unwrap(), None); + assert_eq!(feature.field_as_double(railway_idx).unwrap(), None); assert!(matches!( - feature.field_as_string_by_name("not_a_field").unwrap_err(), + feature.field_index("not_a_field").unwrap_err(), GdalError::InvalidFieldName { field_name, method_name: "OGR_F_GetFieldIndex", @@ -1157,13 +1136,11 @@ mod tests { .with_ymd_and_hms(2018, 1, 4, 0, 0, 0) .unwrap(); - assert_eq!(feature.field_as_datetime_by_name("dt").unwrap(), Some(dt)); + let dt_idx = feature.field_index("dt").unwrap(); + let d_idx = feature.field_index("d").unwrap(); - assert_eq!(feature.field_as_datetime(0).unwrap(), Some(dt)); - - assert_eq!(feature.field_as_datetime_by_name("d").unwrap(), Some(d)); - - assert_eq!(feature.field_as_datetime(1).unwrap(), Some(d)); + assert_eq!(feature.field_as_datetime(dt_idx).unwrap(), Some(dt)); + assert_eq!(feature.field_as_datetime(d_idx).unwrap(), Some(d)); }); with_features("roads.geojson", |mut features| { @@ -1172,13 +1149,12 @@ mod tests { let railway_field = 5; // test null - assert_eq!(feature.field_as_datetime_by_name("railway").unwrap(), None); + assert_eq!(feature.field_as_datetime(railway_field).unwrap(), None); assert_eq!(feature.field_as_datetime(railway_field).unwrap(), None); // test error assert!(matches!( - feature - .field_as_datetime_by_name("not_a_field") + feature.field_index("not_a_field") .unwrap_err(), GdalError::InvalidFieldName { field_name, @@ -1199,7 +1175,8 @@ mod tests { fn test_field_in_layer() { ds_with_layer("three_layer_ds.s3db", "layer_0", |mut layer| { let feature = layer.features().next().unwrap(); - assert_eq!(feature.field("id").unwrap(), None); + let id_idx = feature.field_index("id").unwrap(); + assert_eq!(feature.field(id_idx).unwrap(), None); }); } @@ -1207,8 +1184,9 @@ mod tests { fn test_int_list_field() { with_features("soundg.json", |mut features| { let feature = features.next().unwrap(); + let an_int_list_idx = feature.field_index("an_int_list").unwrap(); assert_eq!( - feature.field("an_int_list").unwrap().unwrap(), + feature.field(an_int_list_idx).unwrap().unwrap(), FieldValue::IntegerListValue(vec![1, 2]) ); }); @@ -1219,8 +1197,9 @@ mod tests { with_features("soundg.json", |mut features| { let mut feature = features.next().unwrap(); let value = FieldValue::IntegerListValue(vec![3, 4, 5]); - feature.set_field("an_int_list", &value).unwrap(); - assert_eq!(feature.field("an_int_list").unwrap().unwrap(), value); + let an_int_list_idx = feature.field_index("an_int_list").unwrap(); + feature.set_field(an_int_list_idx, &value).unwrap(); + assert_eq!(feature.field(an_int_list_idx).unwrap().unwrap(), value); }); } @@ -1228,8 +1207,9 @@ mod tests { fn test_real_list_field() { with_features("soundg.json", |mut features| { let feature = features.next().unwrap(); + let a_real_list_idx = feature.field_index("a_real_list").unwrap(); assert_eq!( - feature.field("a_real_list").unwrap().unwrap(), + feature.field(a_real_list_idx).unwrap().unwrap(), FieldValue::RealListValue(vec![0.1, 0.2]) ); }); @@ -1239,9 +1219,10 @@ mod tests { fn test_set_real_list_field() { with_features("soundg.json", |mut features| { let mut feature = features.next().unwrap(); + let a_real_list_idx = feature.field_index("a_real_list").unwrap(); let value = FieldValue::RealListValue(vec![2.5, 3.0, 4.75]); - feature.set_field("a_real_list", &value).unwrap(); - assert_eq!(feature.field("a_real_list").unwrap().unwrap(), value); + feature.set_field(a_real_list_idx, &value).unwrap(); + assert_eq!(feature.field(a_real_list_idx).unwrap().unwrap(), value); }); } @@ -1249,8 +1230,9 @@ mod tests { fn test_long_list_field() { with_features("soundg.json", |mut features| { let feature = features.next().unwrap(); + let a_long_list_idx = feature.field_index("a_long_list").unwrap(); assert_eq!( - feature.field("a_long_list").unwrap().unwrap(), + feature.field(a_long_list_idx).unwrap().unwrap(), FieldValue::Integer64ListValue(vec![5000000000, 6000000000]) ); }); @@ -1260,18 +1242,20 @@ mod tests { fn test_set_long_list_field() { with_features("soundg.json", |mut features| { let mut feature = features.next().unwrap(); + let a_long_list_idx = feature.field_index("a_long_list").unwrap(); let value = FieldValue::Integer64ListValue(vec![7000000000, 8000000000]); - feature.set_field("a_long_list", &value).unwrap(); - assert_eq!(feature.field("a_long_list").unwrap().unwrap(), value); + feature.set_field(a_long_list_idx, &value).unwrap(); + assert_eq!(feature.field(a_long_list_idx).unwrap().unwrap(), value); }); } #[test] fn test_float_field() { with_feature("roads.geojson", 236194095, |feature| { + let sort_key_idx = feature.field_index("sort_key").unwrap(); assert_almost_eq( feature - .field("sort_key") + .field(sort_key_idx) .unwrap() .unwrap() .into_real() @@ -1281,13 +1265,6 @@ mod tests { }); } - #[test] - fn test_missing_field() { - with_feature("roads.geojson", 236194095, |feature| { - assert!(feature.field("no such field").is_err()); - }); - } - #[test] fn test_geom_accessors() { with_feature("roads.geojson", 236194095, |feature| { @@ -1344,33 +1321,33 @@ mod tests { } #[test] - fn test_write_features() { + fn test_write_features() -> Result<()> { use std::fs; + let name_idx = 0; + let value_idx = 1; + let int_value_idx = 2; + { let driver = DriverManager::get_driver_by_name("GeoJSON").unwrap(); let mut ds = driver .create_vector_only(fixture("output.geojson")) .unwrap(); - let mut layer = ds.create_layer(Default::default()).unwrap(); - layer - .create_defn_fields(&[ - ("Name", OGRFieldType::OFTString), - ("Value", OGRFieldType::OFTReal), - ("Int_value", OGRFieldType::OFTInteger), - ]) - .unwrap(); - layer - .create_feature_fields( - Geometry::from_wkt("POINT (1 2)").unwrap(), - &["Name", "Value", "Int_value"], - &[ - FieldValue::StringValue("Feature 1".to_string()), - FieldValue::RealValue(45.78), - FieldValue::IntegerValue(1), - ], - ) - .unwrap(); + let layer = ds.create_layer(Default::default()).unwrap(); + layer.create_defn_fields(&[ + ("Name", OGRFieldType::OFTString), + ("Value", OGRFieldType::OFTReal), + ("Int_value", OGRFieldType::OFTInteger), + ])?; + + let mut feature = Feature::new(layer.defn())?; + let geometry = Geometry::from_wkt("POINT (1 2)")?; + feature.set_geometry(geometry)?; + feature.set_field_string(name_idx, "Feature 1")?; + feature.set_field_double(value_idx, 45.78)?; + feature.set_field_integer(int_value_idx, 1)?; + feature.create(&layer)?; + // dataset is closed here } @@ -1384,13 +1361,21 @@ mod tests { let ft = layer.features().next().unwrap(); assert_eq!(ft.geometry().unwrap().wkt().unwrap(), "POINT (1 2)"); assert_eq!( - ft.field("Name").unwrap().unwrap().into_string(), + ft.field(name_idx).unwrap().unwrap().into_string(), Some("Feature 1".to_string()) ); - assert_eq!(ft.field("Value").unwrap().unwrap().into_real(), Some(45.78)); - assert_eq!(ft.field("Int_value").unwrap().unwrap().into_int(), Some(1)); + assert_eq!( + ft.field(value_idx).unwrap().unwrap().into_real(), + Some(45.78) + ); + assert_eq!( + ft.field(int_value_idx).unwrap().unwrap().into_int(), + Some(1) + ); } fs::remove_file(fixture("output.geojson")).unwrap(); + + Ok(()) } #[test] @@ -1414,12 +1399,13 @@ mod tests { layer.set_attribute_filter("highway = 'primary'").unwrap(); assert_eq!(layer.features().count(), 1); + let highway_idx = layer.defn().field_index("highway").unwrap(); assert_eq!( layer .features() .next() .unwrap() - .field_as_string_by_name("highway") + .field_as_string(highway_idx) .unwrap() .unwrap(), "primary" @@ -1456,15 +1442,21 @@ mod tests { let mut layer = ds.layer(0).unwrap(); let fids: Vec = layer.features().map(|f| f.fid().unwrap()).collect(); let mut feature = layer.feature(fids[0]).unwrap(); + let id_index = feature.field_index("id").unwrap(); // to original value of the id field in fid 0 is null; we will set it to 1. - feature.set_field_integer("id", 1).ok(); + feature.set_field_integer(id_index, 1).ok(); layer.set_feature(feature).ok(); // now we check that the field is 1. let ds = Dataset::open(&tmp_file).unwrap(); let layer = ds.layer(0).unwrap(); let feature = layer.feature(fids[0]).unwrap(); - let value = feature.field("id").unwrap().unwrap().into_int().unwrap(); + let value = feature + .field(id_index) + .unwrap() + .unwrap() + .into_int() + .unwrap(); assert_eq!(value, 1); } #[test] diff --git a/src/vector/sql.rs b/src/vector/sql.rs index 31f017f0..01652e10 100644 --- a/src/vector/sql.rs +++ b/src/vector/sql.rs @@ -83,12 +83,13 @@ impl Dataset { /// let ds = Dataset::open(Path::new("fixtures/roads.geojson")).unwrap(); /// let query = "SELECT kind, is_bridge, highway FROM roads WHERE highway = 'pedestrian'"; /// let mut result_set = ds.execute_sql(query, None, sql::Dialect::DEFAULT).unwrap().unwrap(); + /// let highway_idx = result_set.defn().field_index("highway").unwrap(); /// /// assert_eq!(10, result_set.feature_count()); /// /// for feature in result_set.features() { /// let highway = feature - /// .field("highway") + /// .field(highway_idx) /// .unwrap() /// .unwrap() /// .into_string() @@ -177,6 +178,7 @@ mod tests { .execute_sql(query, None, sql::Dialect::DEFAULT) .unwrap() .unwrap(); + let highway_idx = result_set.defn().field_index("highway").unwrap(); let field_names: HashSet<_> = result_set .defn() @@ -194,7 +196,7 @@ mod tests { for feature in result_set.features() { let highway = feature - .field("highway") + .field(highway_idx) .unwrap() .unwrap() .into_string() @@ -213,6 +215,7 @@ mod tests { .execute_sql(query, Some(&bbox), sql::Dialect::DEFAULT) .unwrap() .unwrap(); + let highway_idx = result_set.defn().field_index("highway").unwrap(); assert_eq!(2, result_set.feature_count()); let mut correct_fids = HashSet::new(); @@ -222,7 +225,7 @@ mod tests { let mut fids = HashSet::new(); for feature in result_set.features() { let highway = feature - .field("highway") + .field(highway_idx) .unwrap() .unwrap() .into_string() @@ -245,12 +248,13 @@ mod tests { .execute_sql(query, Some(&bbox), sql::Dialect::SQLITE) .unwrap() .unwrap(); + let highway_idx = result_set.defn().field_index("highway").unwrap(); assert_eq!(1, result_set.feature_count()); let mut features: Vec<_> = result_set.features().collect(); let feature = features.pop().unwrap(); let highway = feature - .field("highway") + .field(highway_idx) .unwrap() .unwrap() .into_string()