Skip to content

Commit

Permalink
Merge pull request #313 from joshuachp/fix/delete-interface
Browse files Browse the repository at this point in the history
fix(store): remove interface's properties
  • Loading branch information
harlem88 authored Apr 3, 2024
2 parents 2e393a1 + fcc8bcf commit cea729b
Show file tree
Hide file tree
Showing 13 changed files with 64 additions and 26 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Fixed
- Delete all interface's properties, using the correct mapping, when an
interface is removed
[#313](https://github.com/astarte-platform/astarte-device-sdk-rust/pull/313)

## [0.6.4] - 2024-03-20

## [0.5.3] - 2024-03-20
Expand Down
2 changes: 1 addition & 1 deletion examples/object_datastream/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,5 @@ devices get-samples <DEVICE_NAME>
org.astarte-platform.rust.examples.object-datastream.DeviceDatastream <COMM_ENDPOINT> -c 1
```
Where `<REALM>` is your realm's name, `<DEVICE_ID>` is the device ID from which the data has
been received and `<COMM_ENDPOINT>` is the common part of the aggegate endpoints.
been received and `<COMM_ENDPOINT>` is the common part of the aggregate endpoints.
For this example `<COMM_ENDPOINT>` is fixed to `/23`.
4 changes: 2 additions & 2 deletions examples/registration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ If you have not already done so, make sure that you satisfy the

Once the example has been started it will automatically attempt to register the device to the remote
instance of Astarte.
The retreived credential secret will be displayed in the terminal. Make sure to copy and store it
somewhere safe as there is no way to retreive it later.
The retrieved credential secret will be displayed in the terminal. Make sure to copy and store it
somewhere safe as there is no way to retrieve it later.
1 change: 1 addition & 0 deletions queries/delete_interface.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DELETE FROM propcache WHERE interface = ?
10 changes: 10 additions & 0 deletions sqlx-data.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@
},
"query": "DELETE FROM propcache WHERE interface = ? AND path = ?\n"
},
"5c53a781263f71fd7aa603bbbd63d15316a3f916286577885a1a6d1eb3d790ed": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 1
}
},
"query": "DELETE FROM propcache WHERE interface = ?\n"
},
"baddb61f1e374ef6ebc7ff926a78e210bc4023b9079426bfdff6e73dde5a6a63": {
"describe": {
"columns": [],
Expand Down
2 changes: 1 addition & 1 deletion src/interface/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ impl Interface {
}

/// Getter function for the interface name.
#[deprecated = "Use `interface_name` instead, and manualy convert it to `String` if needed"]
#[deprecated = "Use `interface_name` instead, and manually convert it to `String` if needed"]
pub fn get_name(&self) -> String {
self.interface_name.clone()
}
Expand Down
20 changes: 1 addition & 19 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ where
/// Remove the interface with the name specified as argument.
pub async fn remove_interface(&self, interface_name: &str) -> Result<(), Error> {
let interface = self.remove_interface_from_map(interface_name).await?;
self.remove_properties_from_store(interface_name).await?;
self.store.delete_interface(interface_name).await?;
self.send_introspection().await?;
if interface.ownership() == interface::Ownership::Server {
self.unsubscribe_server_owned_interface(&interface).await?;
Expand Down Expand Up @@ -813,24 +813,6 @@ where
}
}

async fn remove_properties_from_store(&self, interface_name: &str) -> Result<(), Error> {
let interfaces = self.interfaces.read().await;
let mappings = interfaces.get_property(interface_name);

let property = match mappings {
Some(property) => property,
None => return Ok(()),
};

for mapping in property.iter_mappings() {
let path = mapping.endpoint();
self.store.delete_prop(interface_name, path).await?;
debug!("Stored property {}{} deleted", interface_name, path);
}

Ok(())
}

// ------------------------------------------------------------------------
// object types
// ------------------------------------------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions src/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub enum PayloadError {
#[error("couldn't convert the value to AstarteType")]
AstarteType(#[from] TypeError),
/// Expected object, individual data deserialized
#[error("expected object, individual data deserialized intead {0}")]
#[error("expected object, individual data deserialized instead {0}")]
Object(Bson),
/// Missing mapping in payload
#[error["missing mappings in the payload"]]
Expand All @@ -58,7 +58,7 @@ pub enum PayloadError {
#[error("couldn't parse the mapping")]
Mapping(#[from] MappingError),
/// Mismatching type while serializing
#[error("mimatching type while serializing, expected {expected} but got {got}")]
#[error("mismatching type while serializing, expected {expected} but got {got}")]
SerializeType { expected: String, got: String },
/// Couldn't accept unset for mapping without `allow_unset`
#[error("couldn't accept unset if the mapping isn't a property with `allow_unset`")]
Expand Down
7 changes: 7 additions & 0 deletions src/store/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ pub enum StoreError {
/// Could not load all properties.
#[error("could not load all properties")]
LoadAll(#[source] DynError),
/// Could not delete all the interface properties.
#[error("could not delete all the interface properties")]
DeleteInterface(#[source] DynError),
}

impl StoreError {
Expand All @@ -62,4 +65,8 @@ impl StoreError {
pub(crate) fn load_all(err: impl Into<DynError>) -> Self {
Self::LoadAll(err.into())
}

pub(crate) fn delete_interface(err: impl Into<DynError>) -> Self {
Self::DeleteInterface(err.into())
}
}
9 changes: 9 additions & 0 deletions src/store/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,15 @@ impl PropertyStore for MemoryStore {

Ok(props)
}

async fn delete_interface(&self, interface: &str) -> Result<(), Self::Err> {
self.store
.write()
.await
.retain(|k, _v| k.interface != interface);

Ok(())
}
}

/// Key for the in memory store, this let us customize the hash and equality, and use (&str, &str)
Expand Down
10 changes: 9 additions & 1 deletion src/store/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ where
/// Retrieves all property values in the database, together with their interface name, path
/// and major version.
async fn load_all_props(&self) -> Result<Vec<StoredProp>, Self::Err>;
/// Deletes all the properties of the interface from the database.
async fn delete_interface(&self, interface: &str) -> Result<(), Self::Err>;
}

/// Data structure used to return stored properties by a database implementing the AstarteDatabase
Expand Down Expand Up @@ -195,6 +197,12 @@ mod tests {

assert_eq!(props, expected);

// delete interface properties
store.delete_interface("com.test").await.unwrap();
let prop = store.load_prop("com.test", "/test", 1).await.unwrap();

assert_eq!(prop, None);

// test all types
let all_types = [
AstarteType::Double(4.5),
Expand Down Expand Up @@ -229,7 +237,7 @@ mod tests {

/// Test that the error is Send + Sync + 'static to be send across task boundaries.
#[tokio::test]
async fn erro_should_compatible_with_tokio() {
async fn error_should_compatible_with_tokio() {
let mem = StoreWrapper::new(MemoryStore::new());

let exp = AstarteType::Integer(1);
Expand Down
8 changes: 8 additions & 0 deletions src/store/sqlite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,14 @@ impl PropertyStore for SqliteStore {

Ok(res)
}

async fn delete_interface(&self, interface: &str) -> Result<(), Self::Err> {
sqlx::query_file!("queries/delete_interface.sql", interface)
.execute(&self.db_conn)
.await?;

Ok(())
}
}

/// Deserialize a property from the store.
Expand Down
7 changes: 7 additions & 0 deletions src/store/wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,13 @@ where
.await
.map_err(StoreError::load_all)
}

async fn delete_interface(&self, interface: &str) -> Result<(), Self::Err> {
self.store
.delete_interface(interface)
.await
.map_err(StoreError::delete_interface)
}
}

#[cfg(test)]
Expand Down

0 comments on commit cea729b

Please sign in to comment.