diff --git a/README.md b/README.md index 3905ac3..99a0418 100644 --- a/README.md +++ b/README.md @@ -29,10 +29,10 @@ fn main() -> Result<(), Box> { pipeline_name: Some("testPipeline".into()), url: Some("https://dev.pipeline.run/url".into()) }) - .with_id("/dev/pipeline/run/1") + .with_id("/dev/pipeline/run/1".try_into()?) .with_source("https://dev.pipeline.run/source".try_into()?) ) - .with_id("271069a8-fc18-44f1-b38f-9d70a1695819") + .with_id("271069a8-fc18-44f1-b38f-9d70a1695819".try_into()?) .with_source("https://dev.cdevents".try_into()?) ; @@ -52,7 +52,7 @@ fn main() -> Result<(), Box> { let cloudevent_received: Event = cloudevent.clone(); let cdevent_extracted: CDEvent = cloudevent_received.try_into()?; - assert_eq!(cloudevent.id(), cdevent_extracted.id()); + assert_eq!(cloudevent.id(), cdevent_extracted.id().to_string()); assert_eq!(cdevent_expected, cdevent_extracted); Ok(()) } diff --git a/cdevents-sdk/examples/pipelinerun_finished.rs b/cdevents-sdk/examples/pipelinerun_finished.rs index 4bfdef6..12a5c07 100644 --- a/cdevents-sdk/examples/pipelinerun_finished.rs +++ b/cdevents-sdk/examples/pipelinerun_finished.rs @@ -11,10 +11,10 @@ fn main() -> Result<(), Box> { pipeline_name: Some("testPipeline".into()), url: Some("https://dev.pipeline.run/url".into()) }) - .with_id("/dev/pipeline/run/1") + .with_id("/dev/pipeline/run/1".try_into()?) .with_source("https://dev.pipeline.run/source".try_into()?) ) - .with_id("271069a8-fc18-44f1-b38f-9d70a1695819") + .with_id("271069a8-fc18-44f1-b38f-9d70a1695819".try_into()?) .with_source("https://dev.cdevents".try_into()?) ; @@ -34,7 +34,7 @@ fn main() -> Result<(), Box> { let cloudevent_received: Event = cloudevent.clone(); let cdevent_extracted: CDEvent = cloudevent_received.try_into()?; - assert_eq!(cloudevent.id(), cdevent_extracted.id()); + assert_eq!(cloudevent.id(), cdevent_extracted.id().to_string()); assert_eq!(cdevent_expected, cdevent_extracted); Ok(()) } diff --git a/cdevents-sdk/src/cdevent.rs b/cdevents-sdk/src/cdevent.rs index 885da56..ad4b53c 100644 --- a/cdevents-sdk/src/cdevent.rs +++ b/cdevents-sdk/src/cdevent.rs @@ -1,4 +1,4 @@ -use crate::{Context, Subject, UriReference}; +use crate::{Context, Id, Subject, UriReference}; use serde::{ de::{self, Deserializer, MapAccess, Visitor}, Deserialize, Serialize, @@ -22,7 +22,7 @@ pub struct CDEvent { impl From for CDEvent { fn from(subject: Subject) -> Self { let context = Context { - ty: subject.ty().into(), + ty: subject.content().ty().into(), ..Default::default() }; Self { @@ -46,12 +46,12 @@ impl CDEvent { } /// see - pub fn id(&self) -> &str { - self.context.id.as_str() + pub fn id(&self) -> &Id { + &self.context.id } - pub fn with_id(mut self, v: T) -> Self where T: Into { - self.context.id = v.into(); + pub fn with_id(mut self, v: Id) -> Self { + self.context.id = v; self } @@ -83,8 +83,8 @@ impl CDEvent { /// see /// derived from subject.content pub fn ty(&self) -> &str { - //self.context.ty() - self.subject.ty() + //self.subject.content().ty() + self.context.ty.as_str() } /// see @@ -199,14 +199,10 @@ impl<> proptest::arbitrary::Arbitrary for CDEvent { use proptest::prelude::*; ( any::(), - "\\PC*", - any::>(), + any::(), + any::(), ).prop_map(|(subject, id, source)| { - let mut cdevent = CDEvent::from(subject).with_id(id); - if let Some(source) = source { - cdevent = cdevent.with_source(source); - } - cdevent + CDEvent::from(subject).with_id(id).with_source(source) }).boxed() } } diff --git a/cdevents-sdk/src/cloudevents.rs b/cdevents-sdk/src/cloudevents.rs index f7fc72d..0c674be 100644 --- a/cdevents-sdk/src/cloudevents.rs +++ b/cdevents-sdk/src/cloudevents.rs @@ -68,10 +68,10 @@ mod tests { fn test_into_cloudevent() -> Result<(), Box> { let cdevent = CDEvent::from( Subject::from(build_queued::Content{}) - .with_id("subject123") + .with_id("subject123".try_into()?) .with_source("/event/source/123".try_into()?) ) - .with_id("271069a8-fc18-44f1-b38f-9d70a1695819") + .with_id("271069a8-fc18-44f1-b38f-9d70a1695819".try_into()?) .with_source("https://dev.cdevents".try_into()?) ; @@ -82,11 +82,11 @@ mod tests { assert_eq!(cloudevent_via_builder, cloudevent); assert_eq!(cloudevent.id(), "271069a8-fc18-44f1-b38f-9d70a1695819"); - assert_eq!(cloudevent.id(), cdevent.id()); + assert_eq!(cloudevent.id(), cdevent.id().to_string()); let (_, _, data) = cloudevent.take_data(); let cdevent_extracted: CDEvent = data.ok_or(Error::DataNotFoundInCloudEvent)?.try_into()?; - assert_eq!(cloudevent.id(), cdevent_extracted.id()); + assert_eq!(cloudevent.id(), cdevent_extracted.id().to_string()); assert_eq!(cdevent, cdevent_extracted); Ok(()) } diff --git a/cdevents-sdk/src/context.rs b/cdevents-sdk/src/context.rs index cd891f4..7845c5b 100644 --- a/cdevents-sdk/src/context.rs +++ b/cdevents-sdk/src/context.rs @@ -1,12 +1,12 @@ use serde::{Deserialize, Serialize}; -use crate::UriReference; +use crate::{Id, UriReference}; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(deny_unknown_fields)] pub(crate) struct Context { pub(crate) version: String, - pub(crate) id: String, + pub(crate) id: Id, pub(crate) source: UriReference, #[serde(rename = "type")] pub(crate) ty: String, @@ -18,8 +18,8 @@ impl Default for Context { fn default() -> Self { Self { version: "0.3.0".into(), - id: "00000000-0000-0000-0000-000000000000".into(), - source: UriReference::default(), + id: Id::default(), + source: "/undef".try_into().expect("/undef is a valid uri-reference"), ty: "dev.cdevents.undef.undef.0.0.0".into(), timestamp: time::OffsetDateTime::now_utc(), } diff --git a/cdevents-sdk/src/error.rs b/cdevents-sdk/src/error.rs index 5d7260b..51ac340 100644 --- a/cdevents-sdk/src/error.rs +++ b/cdevents-sdk/src/error.rs @@ -1,5 +1,7 @@ use thiserror::Error; +// type Result = std::result::Result; + #[derive(Error, Debug)] pub enum Error { #[error("Empty data in cloudevent")] @@ -10,4 +12,6 @@ pub enum Error { SerdeJsonError( #[from] serde_json::Error), #[error("unknown error")] Unknown, + #[error("{0} should be non-empty")] + EmptyString(&'static str) } diff --git a/cdevents-sdk/src/generated/artifact_packaged.rs b/cdevents-sdk/src/generated/artifact_packaged.rs index 3900f77..e4472a7 100644 --- a/cdevents-sdk/src/generated/artifact_packaged.rs +++ b/cdevents-sdk/src/generated/artifact_packaged.rs @@ -17,7 +17,7 @@ pub struct Content { #[serde(deny_unknown_fields)] pub struct ContentChange { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } diff --git a/cdevents-sdk/src/generated/branch_created.rs b/cdevents-sdk/src/generated/branch_created.rs index 8c479f9..99f44c3 100644 --- a/cdevents-sdk/src/generated/branch_created.rs +++ b/cdevents-sdk/src/generated/branch_created.rs @@ -17,7 +17,7 @@ pub struct Content { #[serde(deny_unknown_fields)] pub struct ContentRepository { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } diff --git a/cdevents-sdk/src/generated/branch_deleted.rs b/cdevents-sdk/src/generated/branch_deleted.rs index 8c479f9..99f44c3 100644 --- a/cdevents-sdk/src/generated/branch_deleted.rs +++ b/cdevents-sdk/src/generated/branch_deleted.rs @@ -17,7 +17,7 @@ pub struct Content { #[serde(deny_unknown_fields)] pub struct ContentRepository { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } diff --git a/cdevents-sdk/src/generated/change_abandoned.rs b/cdevents-sdk/src/generated/change_abandoned.rs index 8c479f9..99f44c3 100644 --- a/cdevents-sdk/src/generated/change_abandoned.rs +++ b/cdevents-sdk/src/generated/change_abandoned.rs @@ -17,7 +17,7 @@ pub struct Content { #[serde(deny_unknown_fields)] pub struct ContentRepository { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } diff --git a/cdevents-sdk/src/generated/change_created.rs b/cdevents-sdk/src/generated/change_created.rs index 8c479f9..99f44c3 100644 --- a/cdevents-sdk/src/generated/change_created.rs +++ b/cdevents-sdk/src/generated/change_created.rs @@ -17,7 +17,7 @@ pub struct Content { #[serde(deny_unknown_fields)] pub struct ContentRepository { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } diff --git a/cdevents-sdk/src/generated/change_merged.rs b/cdevents-sdk/src/generated/change_merged.rs index 8c479f9..99f44c3 100644 --- a/cdevents-sdk/src/generated/change_merged.rs +++ b/cdevents-sdk/src/generated/change_merged.rs @@ -17,7 +17,7 @@ pub struct Content { #[serde(deny_unknown_fields)] pub struct ContentRepository { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } diff --git a/cdevents-sdk/src/generated/change_reviewed.rs b/cdevents-sdk/src/generated/change_reviewed.rs index 8c479f9..99f44c3 100644 --- a/cdevents-sdk/src/generated/change_reviewed.rs +++ b/cdevents-sdk/src/generated/change_reviewed.rs @@ -17,7 +17,7 @@ pub struct Content { #[serde(deny_unknown_fields)] pub struct ContentRepository { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } diff --git a/cdevents-sdk/src/generated/change_updated.rs b/cdevents-sdk/src/generated/change_updated.rs index 8c479f9..99f44c3 100644 --- a/cdevents-sdk/src/generated/change_updated.rs +++ b/cdevents-sdk/src/generated/change_updated.rs @@ -17,7 +17,7 @@ pub struct Content { #[serde(deny_unknown_fields)] pub struct ContentRepository { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } diff --git a/cdevents-sdk/src/generated/incident_detected.rs b/cdevents-sdk/src/generated/incident_detected.rs index 6d0c62a..303f33b 100644 --- a/cdevents-sdk/src/generated/incident_detected.rs +++ b/cdevents-sdk/src/generated/incident_detected.rs @@ -9,7 +9,7 @@ use serde::{Serialize, Deserialize}; #[serde(deny_unknown_fields)] pub struct Content { #[serde(rename = "artifactId", default, skip_serializing_if = "Option::is_none",)] - pub artifact_id: Option, + pub artifact_id: Option, #[serde(rename = "description", default, skip_serializing_if = "Option::is_none",)] pub description: Option, #[serde(rename = "environment",)] @@ -23,7 +23,7 @@ pub struct Content { #[serde(deny_unknown_fields)] pub struct ContentService { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } @@ -33,7 +33,7 @@ pub struct ContentService { #[serde(deny_unknown_fields)] pub struct ContentEnvironment { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } diff --git a/cdevents-sdk/src/generated/incident_reported.rs b/cdevents-sdk/src/generated/incident_reported.rs index ee90dae..a4ac0c1 100644 --- a/cdevents-sdk/src/generated/incident_reported.rs +++ b/cdevents-sdk/src/generated/incident_reported.rs @@ -9,7 +9,7 @@ use serde::{Serialize, Deserialize}; #[serde(deny_unknown_fields)] pub struct Content { #[serde(rename = "artifactId", default, skip_serializing_if = "Option::is_none",)] - pub artifact_id: Option, + pub artifact_id: Option, #[serde(rename = "description", default, skip_serializing_if = "Option::is_none",)] pub description: Option, #[serde(rename = "environment",)] @@ -25,7 +25,7 @@ pub struct Content { #[serde(deny_unknown_fields)] pub struct ContentService { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } @@ -35,7 +35,7 @@ pub struct ContentService { #[serde(deny_unknown_fields)] pub struct ContentEnvironment { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } diff --git a/cdevents-sdk/src/generated/incident_resolved.rs b/cdevents-sdk/src/generated/incident_resolved.rs index 6d0c62a..303f33b 100644 --- a/cdevents-sdk/src/generated/incident_resolved.rs +++ b/cdevents-sdk/src/generated/incident_resolved.rs @@ -9,7 +9,7 @@ use serde::{Serialize, Deserialize}; #[serde(deny_unknown_fields)] pub struct Content { #[serde(rename = "artifactId", default, skip_serializing_if = "Option::is_none",)] - pub artifact_id: Option, + pub artifact_id: Option, #[serde(rename = "description", default, skip_serializing_if = "Option::is_none",)] pub description: Option, #[serde(rename = "environment",)] @@ -23,7 +23,7 @@ pub struct Content { #[serde(deny_unknown_fields)] pub struct ContentService { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } @@ -33,7 +33,7 @@ pub struct ContentService { #[serde(deny_unknown_fields)] pub struct ContentEnvironment { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } diff --git a/cdevents-sdk/src/generated/mod.rs b/cdevents-sdk/src/generated/mod.rs index c64f14e..47f92f2 100644 --- a/cdevents-sdk/src/generated/mod.rs +++ b/cdevents-sdk/src/generated/mod.rs @@ -339,14 +339,140 @@ impl Content { } } - pub fn subject_predicate(&self) -> (&'static str, &'static str){ - let mut split = self.ty().split('.'); - ( - split.nth(2).expect("fargment 2 of ty should always exists"), - split.nth(3).expect("fargment 3 of ty should always exists") - ) + pub fn subject(&self) -> &'static str { + match self { + Self::ArtifactPackaged(_) => "artifact", + Self::ArtifactPublished(_) => "artifact", + Self::ArtifactSigned(_) => "artifact", + Self::BranchCreated(_) => "branch", + Self::BranchDeleted(_) => "branch", + Self::BuildFinished(_) => "build", + Self::BuildQueued(_) => "build", + Self::BuildStarted(_) => "build", + Self::ChangeAbandoned(_) => "change", + Self::ChangeCreated(_) => "change", + Self::ChangeMerged(_) => "change", + Self::ChangeReviewed(_) => "change", + Self::ChangeUpdated(_) => "change", + Self::EnvironmentCreated(_) => "environment", + Self::EnvironmentDeleted(_) => "environment", + Self::EnvironmentModified(_) => "environment", + Self::IncidentDetected(_) => "incident", + Self::IncidentReported(_) => "incident", + Self::IncidentResolved(_) => "incident", + Self::PipelinerunFinished(_) => "pipelineRun", + Self::PipelinerunQueued(_) => "pipelineRun", + Self::PipelinerunStarted(_) => "pipelineRun", + Self::RepositoryCreated(_) => "repository", + Self::RepositoryDeleted(_) => "repository", + Self::RepositoryModified(_) => "repository", + Self::ServiceDeployed(_) => "service", + Self::ServicePublished(_) => "service", + Self::ServiceRemoved(_) => "service", + Self::ServiceRolledback(_) => "service", + Self::ServiceUpgraded(_) => "service", + Self::TaskrunFinished(_) => "taskRun", + Self::TaskrunStarted(_) => "taskRun", + Self::TestcaserunFinished(_) => "testCaseRun", + Self::TestcaserunQueued(_) => "testCaseRun", + Self::TestcaserunStarted(_) => "testCaseRun", + Self::TestoutputPublished(_) => "testOutput", + Self::TestsuiterunFinished(_) => "testSuiteRun", + Self::TestsuiterunQueued(_) => "testSuiteRun", + Self::TestsuiterunStarted(_) => "testSuiteRun", + } } + pub fn predicate(&self) -> &'static str { + match self { + Self::ArtifactPackaged(_) => "packaged", + Self::ArtifactPublished(_) => "published", + Self::ArtifactSigned(_) => "signed", + Self::BranchCreated(_) => "created", + Self::BranchDeleted(_) => "deleted", + Self::BuildFinished(_) => "finished", + Self::BuildQueued(_) => "queued", + Self::BuildStarted(_) => "started", + Self::ChangeAbandoned(_) => "abandoned", + Self::ChangeCreated(_) => "created", + Self::ChangeMerged(_) => "merged", + Self::ChangeReviewed(_) => "reviewed", + Self::ChangeUpdated(_) => "updated", + Self::EnvironmentCreated(_) => "created", + Self::EnvironmentDeleted(_) => "deleted", + Self::EnvironmentModified(_) => "modified", + Self::IncidentDetected(_) => "detected", + Self::IncidentReported(_) => "reported", + Self::IncidentResolved(_) => "resolved", + Self::PipelinerunFinished(_) => "finished", + Self::PipelinerunQueued(_) => "queued", + Self::PipelinerunStarted(_) => "started", + Self::RepositoryCreated(_) => "created", + Self::RepositoryDeleted(_) => "deleted", + Self::RepositoryModified(_) => "modified", + Self::ServiceDeployed(_) => "deployed", + Self::ServicePublished(_) => "published", + Self::ServiceRemoved(_) => "removed", + Self::ServiceRolledback(_) => "rolledback", + Self::ServiceUpgraded(_) => "upgraded", + Self::TaskrunFinished(_) => "finished", + Self::TaskrunStarted(_) => "started", + Self::TestcaserunFinished(_) => "finished", + Self::TestcaserunQueued(_) => "queued", + Self::TestcaserunStarted(_) => "started", + Self::TestoutputPublished(_) => "published", + Self::TestsuiterunFinished(_) => "finished", + Self::TestsuiterunQueued(_) => "queued", + Self::TestsuiterunStarted(_) => "started", + } + } +} + +// due to inconstency in case/format the subject could be not be extracted from the context.type (ty), jsonshema $id, spec filename (shema, examples) +pub fn extract_subject_predicate(ty: &str) -> Option<(&str, &str)>{ + // let mut split = ty.split('.'); + match ty { + ARTIFACT_PACKAGED => Some(("artifact", "packaged")), + ARTIFACT_PUBLISHED => Some(("artifact", "published")), + ARTIFACT_SIGNED => Some(("artifact", "signed")), + BRANCH_CREATED => Some(("branch", "created")), + BRANCH_DELETED => Some(("branch", "deleted")), + BUILD_FINISHED => Some(("build", "finished")), + BUILD_QUEUED => Some(("build", "queued")), + BUILD_STARTED => Some(("build", "started")), + CHANGE_ABANDONED => Some(("change", "abandoned")), + CHANGE_CREATED => Some(("change", "created")), + CHANGE_MERGED => Some(("change", "merged")), + CHANGE_REVIEWED => Some(("change", "reviewed")), + CHANGE_UPDATED => Some(("change", "updated")), + ENVIRONMENT_CREATED => Some(("environment", "created")), + ENVIRONMENT_DELETED => Some(("environment", "deleted")), + ENVIRONMENT_MODIFIED => Some(("environment", "modified")), + INCIDENT_DETECTED => Some(("incident", "detected")), + INCIDENT_REPORTED => Some(("incident", "reported")), + INCIDENT_RESOLVED => Some(("incident", "resolved")), + PIPELINERUN_FINISHED => Some(("pipelineRun", "finished")), + PIPELINERUN_QUEUED => Some(("pipelineRun", "queued")), + PIPELINERUN_STARTED => Some(("pipelineRun", "started")), + REPOSITORY_CREATED => Some(("repository", "created")), + REPOSITORY_DELETED => Some(("repository", "deleted")), + REPOSITORY_MODIFIED => Some(("repository", "modified")), + SERVICE_DEPLOYED => Some(("service", "deployed")), + SERVICE_PUBLISHED => Some(("service", "published")), + SERVICE_REMOVED => Some(("service", "removed")), + SERVICE_ROLLEDBACK => Some(("service", "rolledback")), + SERVICE_UPGRADED => Some(("service", "upgraded")), + TASKRUN_FINISHED => Some(("taskRun", "finished")), + TASKRUN_STARTED => Some(("taskRun", "started")), + TESTCASERUN_FINISHED => Some(("testCaseRun", "finished")), + TESTCASERUN_QUEUED => Some(("testCaseRun", "queued")), + TESTCASERUN_STARTED => Some(("testCaseRun", "started")), + TESTOUTPUT_PUBLISHED => Some(("testOutput", "published")), + TESTSUITERUN_FINISHED => Some(("testSuiteRun", "finished")), + TESTSUITERUN_QUEUED => Some(("testSuiteRun", "queued")), + TESTSUITERUN_STARTED => Some(("testSuiteRun", "started")), + _ => None, + } } impl From for Content { @@ -595,3 +721,91 @@ impl<> proptest::arbitrary::Arbitrary for Content { ].boxed() } } + +// #[cfg(test)] +// mod tests { +// use super::*; +// +// #[test] +// fn test_true() { +// +// assert_eq!(extract_subject_predicate(ARTIFACT_PACKAGED), Some(("artifact","packaged"))); +// +// assert_eq!(extract_subject_predicate(ARTIFACT_PUBLISHED), Some(("artifact","published"))); +// +// assert_eq!(extract_subject_predicate(ARTIFACT_SIGNED), Some(("artifact","signed"))); +// +// assert_eq!(extract_subject_predicate(BRANCH_CREATED), Some(("branch","created"))); +// +// assert_eq!(extract_subject_predicate(BRANCH_DELETED), Some(("branch","deleted"))); +// +// assert_eq!(extract_subject_predicate(BUILD_FINISHED), Some(("build","finished"))); +// +// assert_eq!(extract_subject_predicate(BUILD_QUEUED), Some(("build","queued"))); +// +// assert_eq!(extract_subject_predicate(BUILD_STARTED), Some(("build","started"))); +// +// assert_eq!(extract_subject_predicate(CHANGE_ABANDONED), Some(("change","abandoned"))); +// +// assert_eq!(extract_subject_predicate(CHANGE_CREATED), Some(("change","created"))); +// +// assert_eq!(extract_subject_predicate(CHANGE_MERGED), Some(("change","merged"))); +// +// assert_eq!(extract_subject_predicate(CHANGE_REVIEWED), Some(("change","reviewed"))); +// +// assert_eq!(extract_subject_predicate(CHANGE_UPDATED), Some(("change","updated"))); +// +// assert_eq!(extract_subject_predicate(ENVIRONMENT_CREATED), Some(("environment","created"))); +// +// assert_eq!(extract_subject_predicate(ENVIRONMENT_DELETED), Some(("environment","deleted"))); +// +// assert_eq!(extract_subject_predicate(ENVIRONMENT_MODIFIED), Some(("environment","modified"))); +// +// assert_eq!(extract_subject_predicate(INCIDENT_DETECTED), Some(("incident","detected"))); +// +// assert_eq!(extract_subject_predicate(INCIDENT_REPORTED), Some(("incident","reported"))); +// +// assert_eq!(extract_subject_predicate(INCIDENT_RESOLVED), Some(("incident","resolved"))); +// +// assert_eq!(extract_subject_predicate(PIPELINERUN_FINISHED), Some(("pipelineRun","finished"))); +// +// assert_eq!(extract_subject_predicate(PIPELINERUN_QUEUED), Some(("pipelineRun","queued"))); +// +// assert_eq!(extract_subject_predicate(PIPELINERUN_STARTED), Some(("pipelineRun","started"))); +// +// assert_eq!(extract_subject_predicate(REPOSITORY_CREATED), Some(("repository","created"))); +// +// assert_eq!(extract_subject_predicate(REPOSITORY_DELETED), Some(("repository","deleted"))); +// +// assert_eq!(extract_subject_predicate(REPOSITORY_MODIFIED), Some(("repository","modified"))); +// +// assert_eq!(extract_subject_predicate(SERVICE_DEPLOYED), Some(("service","deployed"))); +// +// assert_eq!(extract_subject_predicate(SERVICE_PUBLISHED), Some(("service","published"))); +// +// assert_eq!(extract_subject_predicate(SERVICE_REMOVED), Some(("service","removed"))); +// +// assert_eq!(extract_subject_predicate(SERVICE_ROLLEDBACK), Some(("service","rolledback"))); +// +// assert_eq!(extract_subject_predicate(SERVICE_UPGRADED), Some(("service","upgraded"))); +// +// assert_eq!(extract_subject_predicate(TASKRUN_FINISHED), Some(("taskRun","finished"))); +// +// assert_eq!(extract_subject_predicate(TASKRUN_STARTED), Some(("taskRun","started"))); +// +// assert_eq!(extract_subject_predicate(TESTCASERUN_FINISHED), Some(("testCaseRun","finished"))); +// +// assert_eq!(extract_subject_predicate(TESTCASERUN_QUEUED), Some(("testCaseRun","queued"))); +// +// assert_eq!(extract_subject_predicate(TESTCASERUN_STARTED), Some(("testCaseRun","started"))); +// +// assert_eq!(extract_subject_predicate(TESTOUTPUT_PUBLISHED), Some(("testOutput","published"))); +// +// assert_eq!(extract_subject_predicate(TESTSUITERUN_FINISHED), Some(("testSuiteRun","finished"))); +// +// assert_eq!(extract_subject_predicate(TESTSUITERUN_QUEUED), Some(("testSuiteRun","queued"))); +// +// assert_eq!(extract_subject_predicate(TESTSUITERUN_STARTED), Some(("testSuiteRun","started"))); +// +// } +// } \ No newline at end of file diff --git a/cdevents-sdk/src/generated/repository_created.rs b/cdevents-sdk/src/generated/repository_created.rs index 7f2ed30..b2d8e60 100644 --- a/cdevents-sdk/src/generated/repository_created.rs +++ b/cdevents-sdk/src/generated/repository_created.rs @@ -9,7 +9,7 @@ use serde::{Serialize, Deserialize}; #[serde(deny_unknown_fields)] pub struct Content { #[serde(rename = "name",)] - pub name: String, + pub name: crate::Name, #[serde(rename = "owner", default, skip_serializing_if = "Option::is_none",)] pub owner: Option, #[serde(rename = "url",)] diff --git a/cdevents-sdk/src/generated/service_deployed.rs b/cdevents-sdk/src/generated/service_deployed.rs index 1499d5c..b9fe280 100644 --- a/cdevents-sdk/src/generated/service_deployed.rs +++ b/cdevents-sdk/src/generated/service_deployed.rs @@ -9,7 +9,7 @@ use serde::{Serialize, Deserialize}; #[serde(deny_unknown_fields)] pub struct Content { #[serde(rename = "artifactId",)] - pub artifact_id: String, + pub artifact_id: crate::Id, #[serde(rename = "environment",)] pub environment: ContentEnvironment, } @@ -19,7 +19,7 @@ pub struct Content { #[serde(deny_unknown_fields)] pub struct ContentEnvironment { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } diff --git a/cdevents-sdk/src/generated/service_published.rs b/cdevents-sdk/src/generated/service_published.rs index 2740c04..e458076 100644 --- a/cdevents-sdk/src/generated/service_published.rs +++ b/cdevents-sdk/src/generated/service_published.rs @@ -17,7 +17,7 @@ pub struct Content { #[serde(deny_unknown_fields)] pub struct ContentEnvironment { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } diff --git a/cdevents-sdk/src/generated/service_removed.rs b/cdevents-sdk/src/generated/service_removed.rs index 2740c04..e458076 100644 --- a/cdevents-sdk/src/generated/service_removed.rs +++ b/cdevents-sdk/src/generated/service_removed.rs @@ -17,7 +17,7 @@ pub struct Content { #[serde(deny_unknown_fields)] pub struct ContentEnvironment { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } diff --git a/cdevents-sdk/src/generated/service_rolledback.rs b/cdevents-sdk/src/generated/service_rolledback.rs index 1499d5c..b9fe280 100644 --- a/cdevents-sdk/src/generated/service_rolledback.rs +++ b/cdevents-sdk/src/generated/service_rolledback.rs @@ -9,7 +9,7 @@ use serde::{Serialize, Deserialize}; #[serde(deny_unknown_fields)] pub struct Content { #[serde(rename = "artifactId",)] - pub artifact_id: String, + pub artifact_id: crate::Id, #[serde(rename = "environment",)] pub environment: ContentEnvironment, } @@ -19,7 +19,7 @@ pub struct Content { #[serde(deny_unknown_fields)] pub struct ContentEnvironment { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } diff --git a/cdevents-sdk/src/generated/service_upgraded.rs b/cdevents-sdk/src/generated/service_upgraded.rs index 1499d5c..b9fe280 100644 --- a/cdevents-sdk/src/generated/service_upgraded.rs +++ b/cdevents-sdk/src/generated/service_upgraded.rs @@ -9,7 +9,7 @@ use serde::{Serialize, Deserialize}; #[serde(deny_unknown_fields)] pub struct Content { #[serde(rename = "artifactId",)] - pub artifact_id: String, + pub artifact_id: crate::Id, #[serde(rename = "environment",)] pub environment: ContentEnvironment, } @@ -19,7 +19,7 @@ pub struct Content { #[serde(deny_unknown_fields)] pub struct ContentEnvironment { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } diff --git a/cdevents-sdk/src/generated/taskrun_finished.rs b/cdevents-sdk/src/generated/taskrun_finished.rs index 8603566..d47c3f7 100644 --- a/cdevents-sdk/src/generated/taskrun_finished.rs +++ b/cdevents-sdk/src/generated/taskrun_finished.rs @@ -25,7 +25,7 @@ pub struct Content { #[serde(deny_unknown_fields)] pub struct ContentPipelineRun { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } diff --git a/cdevents-sdk/src/generated/taskrun_started.rs b/cdevents-sdk/src/generated/taskrun_started.rs index 3edb228..3f76d68 100644 --- a/cdevents-sdk/src/generated/taskrun_started.rs +++ b/cdevents-sdk/src/generated/taskrun_started.rs @@ -21,7 +21,7 @@ pub struct Content { #[serde(deny_unknown_fields)] pub struct ContentPipelineRun { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } diff --git a/cdevents-sdk/src/generated/testcaserun_finished.rs b/cdevents-sdk/src/generated/testcaserun_finished.rs index 6d2051b..c6d4414 100644 --- a/cdevents-sdk/src/generated/testcaserun_finished.rs +++ b/cdevents-sdk/src/generated/testcaserun_finished.rs @@ -27,7 +27,7 @@ pub struct Content { #[serde(deny_unknown_fields)] pub struct ContentTestSuiteRun { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } @@ -37,7 +37,7 @@ pub struct ContentTestSuiteRun { #[serde(deny_unknown_fields)] pub struct ContentTestCase { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "name", default, skip_serializing_if = "Option::is_none",)] pub name: Option, #[serde(rename = "type", default, skip_serializing_if = "Option::is_none",)] @@ -53,7 +53,7 @@ pub struct ContentTestCase { #[serde(deny_unknown_fields)] pub struct ContentEnvironment { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } diff --git a/cdevents-sdk/src/generated/testcaserun_queued.rs b/cdevents-sdk/src/generated/testcaserun_queued.rs index c42dfb2..3c5c12c 100644 --- a/cdevents-sdk/src/generated/testcaserun_queued.rs +++ b/cdevents-sdk/src/generated/testcaserun_queued.rs @@ -33,7 +33,7 @@ pub struct ContentTrigger { #[serde(deny_unknown_fields)] pub struct ContentTestSuiteRun { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } @@ -43,7 +43,7 @@ pub struct ContentTestSuiteRun { #[serde(deny_unknown_fields)] pub struct ContentTestCase { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "name", default, skip_serializing_if = "Option::is_none",)] pub name: Option, #[serde(rename = "type", default, skip_serializing_if = "Option::is_none",)] @@ -59,7 +59,7 @@ pub struct ContentTestCase { #[serde(deny_unknown_fields)] pub struct ContentEnvironment { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } diff --git a/cdevents-sdk/src/generated/testcaserun_started.rs b/cdevents-sdk/src/generated/testcaserun_started.rs index c42dfb2..3c5c12c 100644 --- a/cdevents-sdk/src/generated/testcaserun_started.rs +++ b/cdevents-sdk/src/generated/testcaserun_started.rs @@ -33,7 +33,7 @@ pub struct ContentTrigger { #[serde(deny_unknown_fields)] pub struct ContentTestSuiteRun { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } @@ -43,7 +43,7 @@ pub struct ContentTestSuiteRun { #[serde(deny_unknown_fields)] pub struct ContentTestCase { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "name", default, skip_serializing_if = "Option::is_none",)] pub name: Option, #[serde(rename = "type", default, skip_serializing_if = "Option::is_none",)] @@ -59,7 +59,7 @@ pub struct ContentTestCase { #[serde(deny_unknown_fields)] pub struct ContentEnvironment { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } diff --git a/cdevents-sdk/src/generated/testoutput_published.rs b/cdevents-sdk/src/generated/testoutput_published.rs index 675acbc..b4a146a 100644 --- a/cdevents-sdk/src/generated/testoutput_published.rs +++ b/cdevents-sdk/src/generated/testoutput_published.rs @@ -23,7 +23,7 @@ pub struct Content { #[serde(deny_unknown_fields)] pub struct ContentTestCaseRun { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } diff --git a/cdevents-sdk/src/generated/testsuiterun_finished.rs b/cdevents-sdk/src/generated/testsuiterun_finished.rs index a59e593..824bfb6 100644 --- a/cdevents-sdk/src/generated/testsuiterun_finished.rs +++ b/cdevents-sdk/src/generated/testsuiterun_finished.rs @@ -25,7 +25,7 @@ pub struct Content { #[serde(deny_unknown_fields)] pub struct ContentTestSuite { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "name", default, skip_serializing_if = "Option::is_none",)] pub name: Option, #[serde(rename = "uri", default, skip_serializing_if = "Option::is_none",)] @@ -39,7 +39,7 @@ pub struct ContentTestSuite { #[serde(deny_unknown_fields)] pub struct ContentEnvironment { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } diff --git a/cdevents-sdk/src/generated/testsuiterun_queued.rs b/cdevents-sdk/src/generated/testsuiterun_queued.rs index 5fc5ac1..d5cae30 100644 --- a/cdevents-sdk/src/generated/testsuiterun_queued.rs +++ b/cdevents-sdk/src/generated/testsuiterun_queued.rs @@ -31,7 +31,7 @@ pub struct ContentTrigger { #[serde(deny_unknown_fields)] pub struct ContentTestSuite { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "name", default, skip_serializing_if = "Option::is_none",)] pub name: Option, #[serde(rename = "url", default, skip_serializing_if = "Option::is_none",)] @@ -45,7 +45,7 @@ pub struct ContentTestSuite { #[serde(deny_unknown_fields)] pub struct ContentEnvironment { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } diff --git a/cdevents-sdk/src/generated/testsuiterun_started.rs b/cdevents-sdk/src/generated/testsuiterun_started.rs index f735c42..9c27a7d 100644 --- a/cdevents-sdk/src/generated/testsuiterun_started.rs +++ b/cdevents-sdk/src/generated/testsuiterun_started.rs @@ -31,7 +31,7 @@ pub struct ContentTrigger { #[serde(deny_unknown_fields)] pub struct ContentTestSuite { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "name", default, skip_serializing_if = "Option::is_none",)] pub name: Option, #[serde(rename = "uri", default, skip_serializing_if = "Option::is_none",)] @@ -45,7 +45,7 @@ pub struct ContentTestSuite { #[serde(deny_unknown_fields)] pub struct ContentEnvironment { #[serde(rename = "id",)] - pub id: String, + pub id: crate::Id, #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] pub source: Option, } diff --git a/cdevents-sdk/src/id.rs b/cdevents-sdk/src/id.rs new file mode 100644 index 0000000..ccebdc6 --- /dev/null +++ b/cdevents-sdk/src/id.rs @@ -0,0 +1,88 @@ +use std::{fmt::{Display, Formatter}, str::FromStr}; + +use serde::{Deserialize, Serialize}; + +pub type Id = NonEmptyString; +pub type Name = NonEmptyString; + +/// A non-empty string. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] +pub struct NonEmptyString(String); + +impl NonEmptyString { + pub fn as_str(&self) -> &str { + &self.0.as_str() + } +} + +impl Default for NonEmptyString { + fn default() -> Self { + NonEmptyString("00000000-0000-0000-0000-000000000000".to_owned()) + } +} + +impl From for String { + fn from(id: NonEmptyString) -> Self { + id.0 + } +} +impl TryFrom for NonEmptyString { + type Error = crate::Error; + + fn try_from(value: String) -> Result { + if value.is_empty() { + return Err(crate::Error::EmptyString("id")) + } + Ok(Self(value)) + } +} + +impl TryFrom<&str> for NonEmptyString { + type Error = crate::Error; + + fn try_from(value: &str) -> Result { + if value.is_empty() { + return Err(crate::Error::EmptyString("id")) + } + Ok(Self(value.to_owned())) + } +} + +impl FromStr for NonEmptyString { + type Err = crate::Error; + + fn from_str(s: &str) -> Result { + Self::try_from(s) + } +} + +impl Display for NonEmptyString { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl From<&NonEmptyString> for String { + fn from(id: &NonEmptyString) -> Self { + id.0.clone() + } +} + +impl AsRef for NonEmptyString { + fn as_ref(&self) -> &str { + &self.0 + } +} + +#[cfg(feature = "testkit")] +impl<> proptest::arbitrary::Arbitrary for NonEmptyString { + type Parameters = (); + type Strategy = proptest::strategy::BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + use proptest::prelude::*; + "\\PC+".prop_map(|id| + id.try_into().expect("generate valid id") + ).boxed() + } +} \ No newline at end of file diff --git a/cdevents-sdk/src/lib.rs b/cdevents-sdk/src/lib.rs index 819f4f8..76887c5 100644 --- a/cdevents-sdk/src/lib.rs +++ b/cdevents-sdk/src/lib.rs @@ -8,12 +8,14 @@ mod context; pub mod cloudevents; mod error; mod generated; +mod id; pub(crate) mod serde; mod subject; mod uri; mod uri_reference; pub use cdevent::*; +pub use id::*; pub(crate) use context::*; pub use error::*; pub use generated::*; diff --git a/cdevents-sdk/src/subject.rs b/cdevents-sdk/src/subject.rs index c58f0f0..f120a4f 100644 --- a/cdevents-sdk/src/subject.rs +++ b/cdevents-sdk/src/subject.rs @@ -2,7 +2,7 @@ use std::str::FromStr; use serde::{Deserialize, Serialize}; -use crate::{Content, UriReference}; +use crate::{Content, Id, UriReference}; /// see #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] @@ -11,7 +11,7 @@ pub struct Subject { #[serde(rename = "content")] content: Content, #[serde(rename = "id")] - id: String, + id: Id, #[serde( rename = "source", default, @@ -24,13 +24,12 @@ pub struct Subject { impl Subject { /// see - pub fn id(&self) -> &str { + pub fn id(&self) -> &Id { &self.id } - pub fn with_id(mut self, id: T) -> Self - where T: Into { - self.id = id.into(); + pub fn with_id(mut self, id: Id) -> Self { + self.id = id; self } @@ -60,7 +59,8 @@ impl Subject { id: json["id"] .as_str() .ok_or_else(|| serde::de::Error::missing_field("id"))? - .to_string(), + .try_into() + .map_err(serde::de::Error::custom)?, ty: json["type"] .as_str() .ok_or_else(|| serde::de::Error::missing_field("type"))? @@ -79,10 +79,13 @@ impl Subject { impl From for Subject where T: Into{ fn from(content: T) -> Self { let content = content.into(); - let ty = content.ty().to_owned(); + let ty = crate::extract_subject_predicate(content.ty()) + .map(|(s, _)| s) + .unwrap_or("unknown") + .to_owned(); Self { content, - id: String::new(), + id: Id::default(), source: None, ty, } @@ -97,7 +100,7 @@ impl<> proptest::arbitrary::Arbitrary for Subject { use proptest::prelude::*; ( any::(), - "\\PC*", + any::(), any::>(), ).prop_map(|(content, id, source)| { let mut subject = Subject::from(content).with_id(id); diff --git a/cdevents-sdk/src/uri_reference.rs b/cdevents-sdk/src/uri_reference.rs index 0af5fb9..53b48d7 100644 --- a/cdevents-sdk/src/uri_reference.rs +++ b/cdevents-sdk/src/uri_reference.rs @@ -75,7 +75,7 @@ impl<> proptest::arbitrary::Arbitrary for UriReference { fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { use proptest::prelude::*; (prop_oneof![ - "/[a-z_\\-/]*".prop_map(|s| UriReference::from_str(&s).unwrap()), + "\\/[a-z_\\-\\/]+".prop_map(|s| UriReference::from_str(&s).unwrap()), Just("https://example.com/").prop_map(|s| UriReference::from_str(&s).unwrap()), ]).boxed() } diff --git a/cdevents-sdk/tests/specs.rs b/cdevents-sdk/tests/specs.rs index be3d313..e2b6e70 100644 --- a/cdevents-sdk/tests/specs.rs +++ b/cdevents-sdk/tests/specs.rs @@ -32,7 +32,7 @@ fn for_each_example(#[files("../cdevents-spec/examples/*.json")] path: PathBuf) fn check_against_schema(json: &serde_json::Value, ty: &str) { let (subject, predicate) = cdevents_sdk::extract_subject_predicate(ty).expect("valid type: {ty}"); - let schemapath = format!("../cdevents-spec/schemas/{subject}{predicate}.json"); + let schemapath = format!("../cdevents-spec/schemas/{subject}{predicate}.json").to_lowercase(); //TODO optimize to not recompile a previously read schema let mut schemas = Schemas::new(); let mut compiler = Compiler::new(); diff --git a/generator/src/main.rs b/generator/src/main.rs index 2cf0425..325e56a 100644 --- a/generator/src/main.rs +++ b/generator/src/main.rs @@ -46,18 +46,15 @@ fn main() -> Result<()> { if let Some(extension) = path.extension() { if extension == "json" { let json: Value = serde_json::from_str(&std::fs::read_to_string(&path)?)?; - let (rust_module, context_type, code) = generate_variant(&hbs, json) + let (variant_info, code) = generate_variant(&hbs, json) .with_context(|| format!("failed to generate variant on {:?}", &path))?; let file = settings .dest - .join(cruet::to_snake_case(&rust_module)) + .join(cruet::to_snake_case(&variant_info.rust_module)) .with_extension("rs"); //TODO use a formatter like https://crates.io/crates/prettyplease? fs::write(file, code)?; - variants.push(VariantInfo { - context_type, - rust_module, - }); + variants.push(variant_info); } } } @@ -71,7 +68,7 @@ fn main() -> Result<()> { Ok(()) } -fn generate_variant(hbs: &Handlebars, jsonschema: Value) -> Result<(String, String, String)> { +fn generate_variant(hbs: &Handlebars, jsonschema: Value) -> Result<(VariantInfo, String)> { // let id = jsonschema["$id"] // .as_str() // .ok_or(anyhow!("$id not found or not a string")) @@ -90,11 +87,23 @@ fn generate_variant(hbs: &Handlebars, jsonschema: Value) -> Result<(String, Stri .to_string(); let fragments = context_type.split('.').collect::>(); - let module_name = format!("{}_{}", fragments[2], fragments[3]).to_snake_case(); + let rust_module = format!("{}_{}", fragments[2], fragments[3]).to_snake_case(); + let predicate = fragments[3].to_owned(); + // due to inconstency in case/format the subject could be not be extracted from the context.type (ty), jsonshema $id, spec filename (shema, examples) + let subject = jsonschema["properties"]["subject"]["properties"]["type"]["default"] + .as_str() + .unwrap_or_default() + .to_string(); let data = build_data_for_variants(jsonschema); let code = hbs.render("variant", &data)?; - Ok((module_name.to_string(), context_type, code)) + let variant_info = VariantInfo { + context_type, + rust_module, + subject, + predicate, + }; + Ok((variant_info, code)) } fn generate_module(hbs: &Handlebars, variants: &[VariantInfo]) -> Result<(String, String)> { @@ -133,6 +142,8 @@ struct TypeInfo { struct VariantInfo { context_type: String, rust_module: String, + subject: String, + predicate: String, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -183,12 +194,22 @@ fn collect_structs( // type_declaration: "http::Uri".to_string(), // serde_with: Some("crate::serde::uri".to_string()), // }, - //TODO manage enum _ => match json_definition["enum"].as_array() { - None => TypeInfo { - type_declaration: "String".to_string(), - ..Default::default() - }, + None => { + let type_declaration = + match (field_names.last(), json_definition["minLength"].as_i64()) { + (Some(&"id"), _) => "crate::Id", + (Some(&"name"), Some(1)) => "crate::Name", + (Some(x), Some(1)) if x.ends_with("Id") => "crate::Id", + (Some(x), Some(1)) if x.ends_with("Name") => "crate::Name", + _ => "String", + } + .to_string(); + TypeInfo { + type_declaration, + ..Default::default() + } + } Some(values) => { let default_value = json_definition["default"].as_str(); let values = values diff --git a/generator/templates/mod.hbs b/generator/templates/mod.hbs index e8b2625..51f4665 100644 --- a/generator/templates/mod.hbs +++ b/generator/templates/mod.hbs @@ -45,14 +45,32 @@ impl Content { } } - pub fn subject_predicate(&self) -> (&'static str, &'static str){ - let mut split = self.ty().split('.'); - ( - split.nth(2).expect("fargment 2 of ty should always exists"), - split.nth(3).expect("fargment 3 of ty should always exists") - ) + pub fn subject(&self) -> &'static str { + match self { + {{#each variants }} + Self::{{to_class_case this.rust_module}}(_) => "{{ this.subject }}", + {{/each}} + } } + pub fn predicate(&self) -> &'static str { + match self { + {{#each variants }} + Self::{{to_class_case this.rust_module}}(_) => "{{ this.predicate }}", + {{/each}} + } + } +} + +// due to inconstency in case/format the subject could be not be extracted from the context.type (ty), jsonshema $id, spec filename (shema, examples) +pub fn extract_subject_predicate(ty: &str) -> Option<(&str, &str)>{ + // let mut split = ty.split('.'); + match ty { + {{#each variants }} + {{to_screaming_snake_case this.rust_module}} => Some(("{{ this.subject }}", "{{ this.predicate }}")), + {{/each}} + _ => None, + } } {{#each variants }} @@ -77,3 +95,15 @@ impl<> proptest::arbitrary::Arbitrary for Content { ].boxed() } } + +// #[cfg(test)] +// mod tests { +// use super::*; +// +// #[test] +// fn test_true() { +// {{#each variants }} +// assert_eq!(extract_subject_predicate({{to_screaming_snake_case this.rust_module}}), Some(("{{ this.subject }}","{{ this.predicate }}"))); +// {{/each}} +// } +// } \ No newline at end of file