azure_iot_operations_services/
schema_registry.rsuse core::fmt::Debug;
use std::{collections::HashMap, fmt};
use azure_iot_operations_protocol::{common::aio_protocol_error::AIOProtocolError, rpc_command};
use derive_builder::Builder;
use thiserror::Error;
use schemaregistry_gen::schema_registry::client as sr_client_gen;
mod client;
mod schemaregistry_gen;
pub use client::Client;
const DEFAULT_SCHEMA_VERSION: &str = "1";
#[derive(Debug, Error)]
#[error(transparent)]
pub struct Error(#[from] ErrorKind);
impl Error {
#[must_use]
pub fn kind(&self) -> &ErrorKind {
&self.0
}
}
#[derive(Error, Debug)]
#[allow(clippy::large_enum_variant)]
pub enum ErrorKind {
#[error(transparent)]
AIOProtocolError(#[from] AIOProtocolError),
#[error(transparent)]
InvalidRequestArgument(#[from] rpc_command::invoker::RequestBuilderError),
#[error("{0:?}")]
ServiceError(#[from] ServiceError),
}
#[derive(Debug, Clone)]
#[repr(i32)]
pub enum ErrorCode {
BadRequest = 400,
InternalError = 500,
NotFound = 404,
}
#[derive(Debug, Clone)]
pub struct ErrorDetails {
pub code: Option<String>,
pub correlation_id: Option<String>,
pub message: Option<String>,
}
#[derive(Debug, Clone)]
pub enum ErrorTarget {
DescriptionProperty,
DisplayNameProperty,
FormatProperty,
NameProperty,
SchemaArmResource,
SchemaContentProperty,
SchemaRegistryArmResource,
SchemaTypeProperty,
SchemaVersionArmResource,
TagsProperty,
VersionProperty,
}
#[derive(Debug, Clone)]
pub struct ServiceError {
pub code: ErrorCode,
pub details: Option<ErrorDetails>,
pub inner_error: Option<ErrorDetails>,
pub message: String,
pub target: Option<ErrorTarget>,
}
impl From<sr_client_gen::SchemaRegistryErrorCode> for ErrorCode {
fn from(code: sr_client_gen::SchemaRegistryErrorCode) -> Self {
match code {
sr_client_gen::SchemaRegistryErrorCode::BadRequest => ErrorCode::BadRequest,
sr_client_gen::SchemaRegistryErrorCode::InternalError => ErrorCode::InternalError,
sr_client_gen::SchemaRegistryErrorCode::NotFound => ErrorCode::NotFound,
}
}
}
impl From<sr_client_gen::SchemaRegistryErrorDetails> for ErrorDetails {
fn from(details: sr_client_gen::SchemaRegistryErrorDetails) -> Self {
ErrorDetails {
code: details.code,
correlation_id: details.correlation_id,
message: details.message,
}
}
}
impl From<sr_client_gen::SchemaRegistryErrorTarget> for ErrorTarget {
fn from(target: sr_client_gen::SchemaRegistryErrorTarget) -> Self {
match target {
sr_client_gen::SchemaRegistryErrorTarget::DescriptionProperty => {
ErrorTarget::DescriptionProperty
}
sr_client_gen::SchemaRegistryErrorTarget::DisplayNameProperty => {
ErrorTarget::DisplayNameProperty
}
sr_client_gen::SchemaRegistryErrorTarget::FormatProperty => ErrorTarget::FormatProperty,
sr_client_gen::SchemaRegistryErrorTarget::NameProperty => ErrorTarget::NameProperty,
sr_client_gen::SchemaRegistryErrorTarget::SchemaArmResource => {
ErrorTarget::SchemaArmResource
}
sr_client_gen::SchemaRegistryErrorTarget::SchemaContentProperty => {
ErrorTarget::SchemaContentProperty
}
sr_client_gen::SchemaRegistryErrorTarget::SchemaRegistryArmResource => {
ErrorTarget::SchemaRegistryArmResource
}
sr_client_gen::SchemaRegistryErrorTarget::SchemaTypeProperty => {
ErrorTarget::SchemaTypeProperty
}
sr_client_gen::SchemaRegistryErrorTarget::SchemaVersionArmResource => {
ErrorTarget::SchemaVersionArmResource
}
sr_client_gen::SchemaRegistryErrorTarget::TagsProperty => ErrorTarget::TagsProperty,
sr_client_gen::SchemaRegistryErrorTarget::VersionProperty => {
ErrorTarget::VersionProperty
}
}
}
}
impl From<sr_client_gen::SchemaRegistryError> for ServiceError {
fn from(error: sr_client_gen::SchemaRegistryError) -> Self {
ServiceError {
code: error.code.into(),
details: error.details.map(Into::into),
inner_error: error.inner_error.map(Into::into),
message: error.message,
target: error.target.map(Into::into),
}
}
}
impl fmt::Display for ServiceError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.message)
}
}
impl std::error::Error for ServiceError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Format {
Delta1,
JsonSchemaDraft07,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SchemaType {
MessageSchema,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Schema {
pub description: Option<String>,
pub display_name: Option<String>,
pub format: Format,
pub hash: Option<String>,
pub name: String,
pub namespace: String,
pub schema_content: String,
pub schema_type: SchemaType,
pub tags: HashMap<String, String>,
pub version: String,
}
#[derive(Builder, Clone, Debug, PartialEq, Eq)]
#[builder(setter(into), build_fn(validate = "Self::validate"))]
pub struct PutSchemaRequest {
#[builder(default)]
pub description: Option<String>,
#[builder(default)]
pub display_name: Option<String>,
pub format: Format,
pub schema_content: String,
#[builder(default = "SchemaType::MessageSchema")]
pub schema_type: SchemaType,
#[builder(default)]
pub tags: HashMap<String, String>,
#[builder(default = "DEFAULT_SCHEMA_VERSION.to_string()")]
pub version: String,
}
impl PutSchemaRequestBuilder {
fn validate(&self) -> Result<(), String> {
if let Some(Some(display_name)) = &self.display_name {
if display_name.is_empty() {
return Err("display_name cannot be empty".to_string());
}
}
if let Some(version) = &self.version {
if version.is_empty() {
return Err("version cannot be empty".to_string());
}
}
if let Some(schema_content) = &self.schema_content {
if schema_content.is_empty() {
return Err("schema_content cannot be empty".to_string());
}
}
Ok(())
}
}
#[derive(Builder, Clone, Debug, PartialEq, Eq)]
#[builder(setter(into), build_fn(validate = "Self::validate"))]
pub struct GetSchemaRequest {
name: String,
#[builder(default = "DEFAULT_SCHEMA_VERSION.to_string()")]
version: String,
}
impl GetSchemaRequestBuilder {
fn validate(&self) -> Result<(), String> {
if let Some(name) = &self.name {
if name.is_empty() {
return Err("name cannot be empty".to_string());
}
}
if let Some(version) = &self.version {
if version.is_empty() {
return Err("version cannot be empty".to_string());
}
}
Ok(())
}
}
impl From<Format> for sr_client_gen::Format {
fn from(format: Format) -> Self {
match format {
Format::Delta1 => sr_client_gen::Format::Delta1,
Format::JsonSchemaDraft07 => sr_client_gen::Format::JsonSchemaDraft07,
}
}
}
impl From<sr_client_gen::Format> for Format {
fn from(format: sr_client_gen::Format) -> Self {
match format {
sr_client_gen::Format::Delta1 => Format::Delta1,
sr_client_gen::Format::JsonSchemaDraft07 => Format::JsonSchemaDraft07,
}
}
}
impl From<SchemaType> for sr_client_gen::SchemaType {
fn from(schema_type: SchemaType) -> Self {
match schema_type {
SchemaType::MessageSchema => sr_client_gen::SchemaType::MessageSchema,
}
}
}
impl From<sr_client_gen::SchemaType> for SchemaType {
fn from(schema_type: sr_client_gen::SchemaType) -> Self {
match schema_type {
sr_client_gen::SchemaType::MessageSchema => SchemaType::MessageSchema,
}
}
}
impl From<sr_client_gen::Schema> for Schema {
fn from(schema: sr_client_gen::Schema) -> Self {
Schema {
description: schema.description,
display_name: schema.display_name,
format: schema.format.into(),
hash: schema.hash,
name: schema.name,
namespace: schema.namespace,
schema_content: schema.schema_content,
schema_type: schema.schema_type.into(),
tags: schema.tags.unwrap_or_default(),
version: schema.version,
}
}
}