use super::{
resource::Resource,
version::{RawVersion, ScimVersion},
};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VersionedResource {
resource: Resource,
version: RawVersion,
}
impl VersionedResource {
pub fn new(resource: Resource) -> Self {
let version = Self::get_or_compute_version(&resource);
Self { resource, version }
}
pub fn with_version(resource: Resource, version: RawVersion) -> Self {
Self { resource, version }
}
pub fn resource(&self) -> &Resource {
&self.resource
}
pub fn version(&self) -> &RawVersion {
&self.version
}
pub fn into_resource(self) -> Resource {
self.resource
}
pub fn get_id(&self) -> Option<&str> {
self.resource.get_id()
}
pub fn get_username(&self) -> Option<&str> {
self.resource.get_username()
}
pub fn get_external_id(&self) -> Option<&str> {
self.resource.get_external_id()
}
pub fn get_meta(&self) -> Option<&crate::resource::value_objects::Meta> {
self.resource.get_meta()
}
pub fn get(&self, key: &str) -> Option<&serde_json::Value> {
self.resource.get(key)
}
pub fn get_attribute(&self, attribute_name: &str) -> Option<&serde_json::Value> {
self.resource.get_attribute(attribute_name)
}
pub fn update_resource(&mut self, new_resource: Resource) {
self.version = Self::compute_version(&new_resource);
self.resource = new_resource;
}
pub fn version_matches<F>(&self, expected: &ScimVersion<F>) -> bool {
self.version == *expected
}
pub fn refresh_version(&mut self) {
self.version = Self::compute_version(&self.resource);
}
fn get_or_compute_version(resource: &Resource) -> RawVersion {
if let Some(meta) = resource.get_meta() {
if let Some(meta_version) = meta.version() {
if let Ok(version) = meta_version.parse::<RawVersion>() {
return version;
}
}
}
Self::compute_version(resource)
}
fn compute_version(resource: &Resource) -> RawVersion {
let json_bytes = resource.to_json().unwrap().to_string().into_bytes();
RawVersion::from_content(&json_bytes)
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_versioned_resource_creation() {
let resource = Resource::from_json(
"User".to_string(),
json!({
"id": "123",
"userName": "john.doe",
"active": true
}),
)
.unwrap();
let versioned = VersionedResource::new(resource.clone());
assert_eq!(versioned.get_id(), resource.get_id());
assert!(!versioned.version().as_str().is_empty());
}
#[test]
fn test_versioned_resource_version_changes() {
let resource1 = Resource::from_json(
"User".to_string(),
json!({
"id": "123",
"userName": "john.doe",
"active": true
}),
)
.unwrap();
let resource2 = Resource::from_json(
"User".to_string(),
json!({
"id": "123",
"userName": "john.doe",
"active": false }),
)
.unwrap();
let versioned1 = VersionedResource::new(resource1);
let versioned2 = VersionedResource::new(resource2);
assert!(versioned1.version() != versioned2.version());
}
#[test]
fn test_versioned_resource_update() {
let initial_resource = Resource::from_json(
"User".to_string(),
json!({
"id": "123",
"userName": "john.doe",
"active": true
}),
)
.unwrap();
let mut versioned = VersionedResource::new(initial_resource);
let old_version = versioned.version().clone();
let updated_resource = Resource::from_json(
"User".to_string(),
json!({
"id": "123",
"userName": "john.doe",
"active": false
}),
)
.unwrap();
versioned.update_resource(updated_resource);
assert!(versioned.version() != &old_version);
assert_eq!(versioned.get_id(), Some("123"));
}
#[test]
fn test_versioned_resource_version_matching() {
let resource = Resource::from_json(
"User".to_string(),
json!({
"id": "123",
"userName": "test"
}),
)
.unwrap();
let versioned = VersionedResource::new(resource);
let version_copy = versioned.version().clone();
let different_version = RawVersion::from_hash("different");
assert!(versioned.version_matches(&version_copy));
assert!(!versioned.version_matches(&different_version));
}
#[test]
fn test_versioned_resource_with_version() {
let resource = Resource::from_json("User".to_string(), json!({"id": "123"})).unwrap();
let custom_version = RawVersion::from_hash("custom-version-123");
let versioned = VersionedResource::with_version(resource.clone(), custom_version.clone());
assert_eq!(versioned.get_id(), resource.get_id());
assert_eq!(versioned.version(), &custom_version);
}
#[test]
fn test_versioned_resource_refresh_version() {
let resource =
Resource::from_json("User".to_string(), json!({"id": "123", "data": "test"})).unwrap();
let custom_version = RawVersion::from_hash("custom");
let mut versioned = VersionedResource::with_version(resource, custom_version.clone());
assert_eq!(versioned.version(), &custom_version);
versioned.refresh_version();
assert!(versioned.version() != &custom_version);
}
#[test]
fn test_versioned_resource_serialization() {
let resource = Resource::from_json(
"User".to_string(),
json!({
"id": "123",
"userName": "test.user"
}),
)
.unwrap();
let versioned = VersionedResource::new(resource);
let json = serde_json::to_string(&versioned).unwrap();
let deserialized: VersionedResource = serde_json::from_str(&json).unwrap();
assert_eq!(versioned.get_id(), deserialized.get_id());
assert!(versioned.version() == deserialized.version());
}
}