This is an automated email from the ASF dual-hosted git repository.

hubcio pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iggy.git


The following commit(s) were added to refs/heads/master by this push:
     new 7da163362 fix(sdk): removes topic_id and stream_id from public Stream 
API (#4249)
7da163362 is described below

commit 7da163362572d60feadd6b012baec37b96b95ea8
Author: haubur <[email protected]>
AuthorDate: Sat Oct 10 17:54:17 2026 +0200

    fix(sdk): removes topic_id and stream_id from public Stream API (#4249)
---
 core/connectors/runtime/src/source.rs              |  4 +-
 core/integration/tests/sdk/consumer_offset.rs      |  2 -
 core/integration/tests/sdk/mod.rs                  |  1 +
 core/integration/tests/sdk/stream_builder.rs       | 70 ++++++++++++++++++++++
 core/sdk/src/clients/client.rs                     | 15 ++---
 core/sdk/src/clients/consumer.rs                   | 44 +++++++-------
 core/sdk/src/clients/producer.rs                   | 57 ++++++++++--------
 .../src/stream_builder/build/build_stream_topic.rs | 42 ++++---------
 .../stream_builder/config/config_iggy_consumer.rs  | 58 +-----------------
 .../stream_builder/config/config_iggy_producer.rs  | 57 +-----------------
 .../stream_builder/config/config_iggy_stream.rs    | 32 +++-------
 examples/rust/src/shared/system.rs                 | 10 ++--
 .../rust/src/stream-builder/stream-basic/main.rs   |  3 +-
 .../stream-builder/stream-consumer-config/main.rs  |  6 +-
 .../stream-builder/stream-producer-config/main.rs  |  6 +-
 15 files changed, 172 insertions(+), 235 deletions(-)

diff --git a/core/connectors/runtime/src/source.rs 
b/core/connectors/runtime/src/source.rs
index a6a747b2c..5722f2faa 100644
--- a/core/connectors/runtime/src/source.rs
+++ b/core/connectors/runtime/src/source.rs
@@ -505,12 +505,12 @@ async fn ensure_durable_source_topic(
     stream_name: &str,
     topic_name: &str,
 ) -> Result<(), RuntimeError> {
-    let stream_id = Identifier::try_from(stream_name)?;
+    let stream_id = Identifier::named(stream_name)?;
     if client.get_stream(&stream_id).await?.is_none() {
         client.create_stream(stream_name).await?;
     }
 
-    let topic_id = Identifier::try_from(topic_name)?;
+    let topic_id = Identifier::named(topic_name)?;
     let topic = match client.get_topic(&stream_id, &topic_id).await? {
         Some(topic) => topic,
         None => {
diff --git a/core/integration/tests/sdk/consumer_offset.rs 
b/core/integration/tests/sdk/consumer_offset.rs
index c49cd16af..b12d2b4a3 100644
--- a/core/integration/tests/sdk/consumer_offset.rs
+++ b/core/integration/tests/sdk/consumer_offset.rs
@@ -131,9 +131,7 @@ async fn 
given_standalone_stream_consumer_when_creating_topic_should_select_part
         let topic_name = format!("{TOPIC_NAME}-{partitions_count}");
         let topic_id = Identifier::named(&topic_name).unwrap();
         let config = IggyConsumerConfig::builder()
-            .stream_id(stream_id.clone())
             .stream_name(STREAM_NAME)
-            .topic_id(topic_id.clone())
             .topic_name(topic_name)
             .consumer_name(CONSUMER_NAME)
             .consumer_kind(ConsumerKind::Consumer)
diff --git a/core/integration/tests/sdk/mod.rs 
b/core/integration/tests/sdk/mod.rs
index b9b329866..483aff0c5 100644
--- a/core/integration/tests/sdk/mod.rs
+++ b/core/integration/tests/sdk/mod.rs
@@ -28,3 +28,4 @@ mod producer;
 mod protocol_version;
 mod raw;
 mod send_confirmation;
+mod stream_builder;
diff --git a/core/integration/tests/sdk/stream_builder.rs 
b/core/integration/tests/sdk/stream_builder.rs
new file mode 100644
index 000000000..2632dea42
--- /dev/null
+++ b/core/integration/tests/sdk/stream_builder.rs
@@ -0,0 +1,70 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use iggy::prelude::*;
+use iggy::stream_builder::{IggyConsumerConfig, IggyStreamConsumer};
+use integration::iggy_harness;
+
+const STREAM_NAME: &str = "123";
+const TOPIC_NAME: &str = "stream-builder-topic";
+const CONSUMER_NAME: &str = "stream-builder-consumer";
+
+#[iggy_harness]
+async fn 
given_consumer_config_when_building_twice_should_reuse_the_named_stream_and_topic(
+    harness: &TestHarness,
+) {
+    let client = harness.root_client().await.expect("Root client");
+    let config = consumer_config();
+    let stream_id = Identifier::named(STREAM_NAME).unwrap();
+
+    for build in 1..=2 {
+        let mut consumer = IggyStreamConsumer::build(&client, &config)
+            .await
+            .unwrap_or_else(|err| {
+                panic!("Stream consumer should initialize on build {build}: 
{err}")
+            });
+
+        let streams = client.get_streams().await.expect("Read streams");
+        let stream_names: Vec<&str> = streams.iter().map(|stream| 
stream.name.as_str()).collect();
+        assert_eq!(stream_names, vec![STREAM_NAME]);
+
+        let topics = client.get_topics(&stream_id).await.expect("Read topics");
+        let topic_names: Vec<&str> = topics.iter().map(|topic| 
topic.name.as_str()).collect();
+        assert_eq!(topic_names, vec![TOPIC_NAME]);
+
+        consumer.shutdown().await.expect("Shut down consumer");
+    }
+}
+
+fn consumer_config() -> IggyConsumerConfig {
+    IggyConsumerConfig::builder()
+        .stream_name(STREAM_NAME)
+        .topic_name(TOPIC_NAME)
+        .consumer_name(CONSUMER_NAME)
+        .consumer_kind(ConsumerKind::Consumer)
+        .auto_commit(AutoCommit::Disabled)
+        .batch_length(1)
+        .create_stream_if_not_exists(true)
+        .create_topic_if_not_exists(true)
+        .partitions_count(1)
+        .polling_interval("1ms".parse().unwrap())
+        .polling_strategy(PollingStrategy::first())
+        .polling_retry_interval(NonZeroIggyDuration::ONE_SECOND)
+        .init_retries(0)
+        .init_interval(NonZeroIggyDuration::ONE_SECOND)
+        .build()
+}
diff --git a/core/sdk/src/clients/client.rs b/core/sdk/src/clients/client.rs
index 99c4dc2b8..8f7adc5e8 100644
--- a/core/sdk/src/clients/client.rs
+++ b/core/sdk/src/clients/client.rs
@@ -21,6 +21,7 @@ use crate::clients::client_builder::IggyClientBuilder;
 use crate::http::http_client::HttpClient;
 use crate::http::http_transport::HttpTransport;
 use crate::prelude::EncryptorKind;
+use crate::prelude::Identifier;
 use crate::prelude::IggyConsumerBuilder;
 use crate::prelude::IggyError;
 use crate::prelude::IggyProducerBuilder;
@@ -653,8 +654,8 @@ impl IggyClient {
             self.client.clone(),
             name.to_owned(),
             Consumer::new(name.try_into()?),
-            stream.try_into()?,
-            topic.try_into()?,
+            Identifier::named(stream)?,
+            Identifier::named(topic)?,
             Some(partition),
             self.encryptor.clone(),
             None,
@@ -723,9 +724,9 @@ impl IggyClient {
         Ok(IggyConsumerBuilder::new(
             self.client.clone(),
             name.to_owned(),
-            Consumer::group(name.try_into()?),
-            stream.try_into()?,
-            topic.try_into()?,
+            Consumer::group(Identifier::named(name)?),
+            Identifier::named(stream)?,
+            Identifier::named(topic)?,
             None,
             self.encryptor.clone(),
             None,
@@ -784,9 +785,9 @@ impl IggyClient {
     pub fn producer(&self, stream: &str, topic: &str) -> 
Result<IggyProducerBuilder, IggyError> {
         Ok(IggyProducerBuilder::new(
             self.client.clone(),
-            stream.try_into()?,
+            Identifier::named(stream)?,
             stream.to_owned(),
-            topic.try_into()?,
+            Identifier::named(topic)?,
             topic.to_owned(),
             self.encryptor.clone(),
             self.partitioner.clone(),
diff --git a/core/sdk/src/clients/consumer.rs b/core/sdk/src/clients/consumer.rs
index 52a953c4d..1fb152c29 100644
--- a/core/sdk/src/clients/consumer.rs
+++ b/core/sdk/src/clients/consumer.rs
@@ -944,8 +944,9 @@ impl IggyConsumer {
     ///   [`auto_commit()`](crate::prelude::IggyConsumerBuilder::auto_commit) 
is
     ///   [`AutoCommitWhen::PollingMessages`], checked before anything is 
sent. See
     ///   [Encryption](IggyConsumer#encryption).
-    /// - [`IggyError::StreamNameNotFound`] or 
[`IggyError::TopicNameNotFound`] when the
-    ///   stream or the topic still does not exist once the retries are 
exhausted.
+    /// - [`IggyError::StreamNameNotFound`], [`IggyError::StreamIdNotFound`] 
or [`IggyError::TopicNameNotFound`],
+    ///   [`IggyError::TopicIdNotFound`] when the stream or the topic still 
does not exist once the retries are
+    ///   exhausted.
     /// - [`IggyError::ConsumerGroupNameNotFound`] when the consumer group 
does not exist
     ///   and its auto creation is disabled.
     /// - Any error returned by the server while looking up the stream or the 
topic, or
@@ -1024,17 +1025,26 @@ impl IggyConsumer {
 
             if !stream_exists {
                 error!("Stream: {stream_id} was not found.");
-                return Err(IggyError::StreamNameNotFound(
-                    self.stream_id.get_string_value().unwrap_or_default(),
-                ));
-            };
+                return Err(match stream_id.kind {
+                    IdKind::String => 
IggyError::StreamNameNotFound(stream_id.get_string_value()?),
+                    IdKind::Numeric => {
+                        
IggyError::StreamIdNotFound(Identifier::from_identifier(&stream_id))
+                    }
+                });
+            }
 
             if !topic_exists {
                 error!("Topic: {topic_id} was not found in stream: 
{stream_id}.");
-                return Err(IggyError::TopicNameNotFound(
-                    self.topic_id.get_string_value().unwrap_or_default(),
-                    self.stream_id.get_string_value().unwrap_or_default(),
-                ));
+                return Err(match topic_id.kind {
+                    IdKind::String => IggyError::TopicNameNotFound(
+                        topic_id.get_string_value()?,
+                        stream_id.to_string(),
+                    ),
+                    IdKind::Numeric => IggyError::TopicIdNotFound(
+                        Identifier::from_identifier(&topic_id),
+                        Identifier::from_identifier(&stream_id),
+                    ),
+                });
             }
         }
 
@@ -1156,7 +1166,6 @@ impl IggyConsumer {
             self.create_consumer_group_if_not_exists,
             self.stream_id.clone(),
             self.topic_id.clone(),
-            self.consumer.clone(),
             &self.consumer_name,
             self.joined_consumer_group.clone(),
         )
@@ -1257,7 +1266,6 @@ impl IggyConsumer {
                     create_consumer_group_if_not_exists,
                     stream_id.clone(),
                     topic_id.clone(),
-                    consumer.clone(),
                     &consumer_name,
                     joined_consumer_group.clone(),
                 )
@@ -1420,7 +1428,6 @@ impl IggyConsumer {
         create_consumer_group_if_not_exists: bool,
         stream_id: Arc<Identifier>,
         topic_id: Arc<Identifier>,
-        consumer: Arc<Consumer>,
         consumer_name: &str,
         joined_consumer_group: Arc<AtomicBool>,
     ) -> Result<(), IggyError> {
@@ -1429,12 +1436,7 @@ impl IggyConsumer {
         }
 
         let client = client.read().await;
-        let (name, _id) = match consumer.id.kind {
-            IdKind::Numeric => (consumer_name.to_owned(), 
Some(consumer.id.get_u32_value()?)),
-            IdKind::String => (consumer.id.get_string_value()?, None),
-        };
-
-        let consumer_group_id = name.to_owned().try_into()?;
+        let consumer_group_id = Identifier::named(consumer_name)?;
         trace!(
             "Validating consumer group: {consumer_group_id} for topic: 
{topic_id}, stream: {stream_id}"
         );
@@ -1447,7 +1449,7 @@ impl IggyConsumer {
                 error!("Consumer group does not exist and auto-creation is 
disabled.");
                 let topic_identifier = Identifier::from_identifier(&topic_id);
                 return Err(IggyError::ConsumerGroupNameNotFound(
-                    name.to_owned(),
+                    consumer_name.to_owned(),
                     topic_identifier,
                 ));
             }
@@ -1456,7 +1458,7 @@ impl IggyConsumer {
                 "Creating consumer group: {consumer_group_id} for topic: 
{topic_id}, stream: {stream_id}"
             );
             match client
-                .create_consumer_group(&stream_id, &topic_id, &name)
+                .create_consumer_group(&stream_id, &topic_id, consumer_name)
                 .await
             {
                 Ok(_) => {}
diff --git a/core/sdk/src/clients/producer.rs b/core/sdk/src/clients/producer.rs
index d19defcf2..e94cb02ab 100644
--- a/core/sdk/src/clients/producer.rs
+++ b/core/sdk/src/clients/producer.rs
@@ -109,43 +109,51 @@ impl ProducerCore {
         let client = self.client.clone();
         let client = client.read().await;
         if client.get_stream(&stream_id).await?.is_none() {
+            let name = match stream_id.kind {
+                IdKind::String => stream_id.get_string_value()?,
+                IdKind::Numeric => {
+                    error!(
+                        "Stream: {stream_id} does not exist and cannot be 
created from a numeric identifier."
+                    );
+                    return 
Err(IggyError::StreamIdNotFound(Identifier::from_identifier(
+                        &stream_id,
+                    )));
+                }
+            };
+
             if !self.create_stream_if_not_exists {
                 error!("Stream does not exist and auto-creation is disabled.");
-                return 
Err(IggyError::StreamNameNotFound(self.stream_name.clone()));
+                return Err(IggyError::StreamNameNotFound(name));
             }
 
-            let (name, _id) = match stream_id.kind {
-                IdKind::Numeric => (
-                    self.stream_name.to_owned(),
-                    Some(self.stream_id.get_u32_value()?),
-                ),
-                IdKind::String => (self.stream_id.get_string_value()?, None),
-            };
             info!("Creating stream: {name}");
             client.create_stream(&name).await?;
         }
 
         if client.get_topic(&stream_id, &topic_id).await?.is_none() {
+            let name = match topic_id.kind {
+                IdKind::String => topic_id.get_string_value()?,
+                IdKind::Numeric => {
+                    error!(
+                        "Topic: {topic_id} does not exist and cannot be 
created from a numeric identifier."
+                    );
+                    return Err(IggyError::TopicIdNotFound(
+                        Identifier::from_identifier(&topic_id),
+                        Identifier::from_identifier(&stream_id),
+                    ));
+                }
+            };
+
             if !self.create_topic_if_not_exists {
                 error!("Topic does not exist and auto-creation is disabled.");
-                return Err(IggyError::TopicNameNotFound(
-                    self.topic_name.clone(),
-                    self.stream_name.clone(),
-                ));
+                return Err(IggyError::TopicNameNotFound(name, 
stream_id.to_string()));
             }
 
-            let (name, _id) = match self.topic_id.kind {
-                IdKind::Numeric => (
-                    self.topic_name.to_owned(),
-                    Some(self.topic_id.get_u32_value()?),
-                ),
-                IdKind::String => (self.topic_id.get_string_value()?, None),
-            };
-            info!("Creating topic: {name} for stream: {}", self.stream_name);
+            info!("Creating topic: {name} for stream: {stream_id}");
             client
                 .create_topic(
-                    &self.stream_id,
-                    &self.topic_name,
+                    &stream_id,
+                    &name,
                     &TopicCreateOptions {
                         partitions_count: Some(self.topic_partitions_count),
                         message_expiry: (self.topic_message_expiry != 
IggyExpiry::ServerDefault)
@@ -896,8 +904,9 @@ impl IggyProducer {
     ///
     /// # Errors
     ///
-    /// - [`IggyError::StreamNameNotFound`] or 
[`IggyError::TopicNameNotFound`] when the stream or
-    ///   the topic does not exist and its auto creation is disabled.
+    /// - [`IggyError::StreamNameNotFound`], [`IggyError::StreamIdNotFound`] 
or [`IggyError::TopicNameNotFound`],
+    ///   [`IggyError::TopicIdNotFound`] when the stream or the topic still 
does not exist once the retries are
+    ///   exhausted.
     /// - Any other error the server raised while looking up or creating the 
stream or the topic.
     pub async fn init(&self) -> Result<(), IggyError> {
         self.core.init().await
diff --git a/core/sdk/src/stream_builder/build/build_stream_topic.rs 
b/core/sdk/src/stream_builder/build/build_stream_topic.rs
index beebbcd77..d4a05552f 100644
--- a/core/sdk/src/stream_builder/build/build_stream_topic.rs
+++ b/core/sdk/src/stream_builder/build/build_stream_topic.rs
@@ -17,7 +17,7 @@
  */
 
 use crate::prelude::{
-    IdKind, Identifier, IggyClient, IggyError, StreamClient, TopicClient, 
TopicCreateOptions,
+    Identifier, IggyClient, IggyError, StreamClient, TopicClient, 
TopicCreateOptions,
 };
 
 use crate::stream_builder::IggyConsumerConfig;
@@ -43,13 +43,14 @@ pub(crate) async fn build_iggy_stream_topic_if_not_exists(
     client: &IggyClient,
     config: &IggyConsumerConfig,
 ) -> Result<(), IggyError> {
-    let stream_id = config.stream_id();
     let stream_name = config.stream_name();
-    let topic_id = config.topic_id();
     let topic_name = config.topic_name();
 
+    let stream_id = Identifier::named(stream_name)?;
+    let topic_id = Identifier::named(topic_name)?;
+
     trace!("Check if stream exists.");
-    if client.get_stream(config.stream_id()).await?.is_none() {
+    if client.get_stream(&stream_id).await?.is_none() {
         trace!("Check if stream should be created.");
         if !config.create_stream_if_not_exists() {
             warn!(
@@ -59,17 +60,12 @@ pub(crate) async fn build_iggy_stream_topic_if_not_exists(
             return Ok(());
         }
 
-        let (name, _id) = extract_name_id_from_identifier(stream_id, 
stream_name)?;
-        trace!("Creating stream: {name}");
-        client.create_stream(&name).await?;
+        trace!("Creating stream: {stream_name}");
+        client.create_stream(stream_name).await?;
     }
 
     trace!("Check if topic exists.");
-    if client
-        .get_topic(config.stream_id(), config.topic_id())
-        .await?
-        .is_none()
-    {
+    if client.get_topic(&stream_id, &topic_id).await?.is_none() {
         trace!("Check if topic should be created.");
         if !config.create_topic_if_not_exists() {
             warn!(
@@ -79,18 +75,13 @@ pub(crate) async fn build_iggy_stream_topic_if_not_exists(
             return Ok(());
         }
 
-        let stream_id = config.stream_id();
-        let stream_name = config.stream_name();
-        let topic_partitions_count = config.partitions_count();
-
-        let (name, _id) = extract_name_id_from_identifier(topic_id, 
topic_name)?;
-        trace!("Create topic: {name} for stream: {}", stream_name);
+        trace!("Create topic: {topic_name} for stream: {stream_name}");
         client
             .create_topic(
-                stream_id,
+                &stream_id,
                 topic_name,
                 &TopicCreateOptions {
-                    partitions_count: Some(topic_partitions_count),
+                    partitions_count: Some(config.partitions_count()),
                     ..TopicCreateOptions::default()
                 },
             )
@@ -99,14 +90,3 @@ pub(crate) async fn build_iggy_stream_topic_if_not_exists(
 
     Ok(())
 }
-
-fn extract_name_id_from_identifier(
-    stream_id: &Identifier,
-    stream_name: &str,
-) -> Result<(String, Option<u32>), IggyError> {
-    let (name, id) = match stream_id.kind {
-        IdKind::Numeric => (stream_name.to_owned(), 
Some(stream_id.get_u32_value()?)),
-        IdKind::String => (stream_id.get_string_value()?, None),
-    };
-    Ok((name, id))
-}
diff --git a/core/sdk/src/stream_builder/config/config_iggy_consumer.rs 
b/core/sdk/src/stream_builder/config/config_iggy_consumer.rs
index 83aef80f7..b6da466c6 100644
--- a/core/sdk/src/stream_builder/config/config_iggy_consumer.rs
+++ b/core/sdk/src/stream_builder/config/config_iggy_consumer.rs
@@ -30,12 +30,8 @@ const DEFAULT_PARTITION_ID: u32 = 0;
 #[derive(Builder, Debug, Clone)]
 #[builder(on(String, into))]
 pub struct IggyConsumerConfig {
-    /// Identifier of the stream. Must be unique.
-    stream_id: Identifier,
     /// Name of the stream. Must be unique.
     stream_name: String,
-    /// Identifier of the topic. Must be unique.
-    topic_id: Identifier,
     /// Name of the topic. Must be unique.
     topic_name: String,
     /// The auto-commit configuration for storing the message offset on the 
server. See  `AutoCommit` for details.
@@ -74,13 +70,8 @@ pub struct IggyConsumerConfig {
 
 impl Default for IggyConsumerConfig {
     fn default() -> Self {
-        let stream_id = Identifier::from_str_value("test_stream").unwrap();
-        let topic_id = Identifier::from_str_value("test_topic").unwrap();
-
         Self {
-            stream_id,
             stream_name: "test_stream".to_string(),
-            topic_id,
             topic_name: "test_topic".to_string(),
             auto_commit: AutoCommit::When(AutoCommitWhen::PollingMessages),
             batch_length: 100,
@@ -105,9 +96,7 @@ impl IggyConsumerConfig {
     ///
     /// # Args
     ///
-    /// * `stream_id` - The stream id.
     /// * `stream_name` - The stream name.
-    /// * `topic_id` - The topic id.
     /// * `topic_name` - The topic name.
     /// * `auto_commit` - The auto commit config.
     /// * `batch_length` - The max number of messages to poll in a batch.
@@ -131,9 +120,7 @@ impl IggyConsumerConfig {
     ///
     #[allow(clippy::too_many_arguments)]
     pub fn new(
-        stream_id: Identifier,
         stream_name: String,
-        topic_id: Identifier,
         topic_name: String,
         auto_commit: AutoCommit,
         batch_length: u32,
@@ -150,9 +137,7 @@ impl IggyConsumerConfig {
         init_interval: NonZeroIggyDuration,
     ) -> Self {
         Self {
-            stream_id,
             stream_name,
-            topic_id,
             topic_name,
             auto_commit,
             batch_length,
@@ -189,13 +174,12 @@ impl IggyConsumerConfig {
         batch_length: u32,
         polling_interval: IggyDuration,
     ) -> Result<Self, IggyError> {
-        let stream_id = Identifier::from_str_value(stream)?;
-        let topic_id = Identifier::from_str_value(topic)?;
+        // Validate stream and topic names. Returns IggyError if names are not 
allowed.
+        Identifier::named(stream)?;
+        Identifier::named(topic)?;
 
         Ok(Self {
-            stream_id,
             stream_name: stream.to_string(),
-            topic_id,
             topic_name: topic.to_string(),
             auto_commit: AutoCommit::When(AutoCommitWhen::PollingMessages),
             batch_length,
@@ -222,18 +206,10 @@ impl IggyConsumerConfig {
         self
     }
 
-    pub fn stream_id(&self) -> &Identifier {
-        &self.stream_id
-    }
-
     pub fn stream_name(&self) -> &str {
         &self.stream_name
     }
 
-    pub fn topic_id(&self) -> &Identifier {
-        &self.topic_id
-    }
-
     pub fn topic_name(&self) -> &str {
         &self.topic_name
     }
@@ -335,14 +311,9 @@ mod tests {
 
     #[test]
     fn should_be_equal() {
-        let stream_id = Identifier::from_str_value("test_stream").unwrap();
-        let topic_id = Identifier::from_str_value("test_topic").unwrap();
-
         // Builder is generated by the bon macro
         let config = IggyConsumerConfig::builder()
-            .stream_id(stream_id)
             .stream_name("test_stream".to_string())
-            .topic_id(topic_id)
             .topic_name("test_topic".to_string())
             .auto_commit(AutoCommit::When(AutoCommitWhen::PollingMessages))
             .batch_length(100)
@@ -358,15 +329,7 @@ mod tests {
             .init_interval(NonZeroIggyDuration::from_str("3s").unwrap())
             .build();
 
-        assert_eq!(
-            config.stream_id(),
-            &Identifier::from_str_value("test_stream").unwrap()
-        );
         assert_eq!(config.stream_name(), "test_stream");
-        assert_eq!(
-            config.topic_id(),
-            &Identifier::from_str_value("test_topic").unwrap()
-        );
         assert_eq!(config.topic_name(), "test_topic");
         assert_eq!(
             config.auto_commit(),
@@ -398,13 +361,8 @@ mod tests {
 
     #[test]
     fn should_be_default() {
-        let stream_id = Identifier::from_str_value("test_stream").unwrap();
-        let topic_id = Identifier::from_str_value("test_topic").unwrap();
-
         let config = IggyConsumerConfig::default();
-        assert_eq!(config.stream_id(), &stream_id);
         assert_eq!(config.stream_name(), "test_stream");
-        assert_eq!(config.topic_id(), &topic_id);
         assert_eq!(config.topic_name(), "test_topic");
         assert_eq!(
             config.auto_commit(),
@@ -436,9 +394,7 @@ mod tests {
     #[test]
     fn should_be_new() {
         let config = IggyConsumerConfig::new(
-            Identifier::from_str_value("test_stream").unwrap(),
             "test_stream".to_string(),
-            Identifier::from_str_value("test_topic").unwrap(),
             "test_topic".to_string(),
             AutoCommit::When(AutoCommitWhen::PollingMessages),
             100,
@@ -454,15 +410,7 @@ mod tests {
             Some(3),
             NonZeroIggyDuration::from_str("3s").unwrap(),
         );
-        assert_eq!(
-            config.stream_id(),
-            &Identifier::from_str_value("test_stream").unwrap(),
-        );
         assert_eq!(config.stream_name(), "test_stream");
-        assert_eq!(
-            config.topic_id(),
-            &Identifier::from_str_value("test_topic").unwrap()
-        );
         assert_eq!(config.topic_name(), "test_topic");
         assert_eq!(
             config.auto_commit(),
diff --git a/core/sdk/src/stream_builder/config/config_iggy_producer.rs 
b/core/sdk/src/stream_builder/config/config_iggy_producer.rs
index bfcc7f2d4..9acd2a80a 100644
--- a/core/sdk/src/stream_builder/config/config_iggy_producer.rs
+++ b/core/sdk/src/stream_builder/config/config_iggy_producer.rs
@@ -26,12 +26,8 @@ use std::sync::Arc;
 #[derive(Builder, Debug, Clone)]
 #[builder(on(String, into))]
 pub struct IggyProducerConfig {
-    /// Identifier of the stream. Must be unique.
-    stream_id: Identifier,
     /// Name of the stream. Must be unique.
     stream_name: String,
-    /// Identifier of the topic. Must be unique.
-    topic_id: Identifier,
     /// Name of the topic. Must be unique.
     topic_name: String,
     /// Sets the number of partitions to create for the topic
@@ -57,13 +53,8 @@ pub struct IggyProducerConfig {
 
 impl Default for IggyProducerConfig {
     fn default() -> Self {
-        let stream_id = Identifier::from_str_value("test_stream").unwrap();
-        let topic_id = Identifier::from_str_value("test_topic").unwrap();
-
         Self {
-            stream_id,
             stream_name: "test_stream".to_string(),
-            topic_id,
             topic_name: "test_topic".to_string(),
             batch_length: 100,
             linger_time: IggyDuration::from_str("5ms").unwrap(),
@@ -82,9 +73,7 @@ impl IggyProducerConfig {
     ///
     /// # Args
     ///
-    /// * `stream_id` - The stream identifier.
     /// * `stream_name` - The stream name.
-    /// * `topic_id` - The topic identifier.
     /// * `topic_name` - The topic name.
     /// * `topic_partitions_count` - The number of partitions to create.
     /// * `batch_length` - The max number of messages to send in a batch.
@@ -99,9 +88,7 @@ impl IggyProducerConfig {
     ///
     #[allow(clippy::too_many_arguments)]
     pub fn new(
-        stream_id: Identifier,
         stream_name: String,
-        topic_id: Identifier,
         topic_name: String,
         topic_partitions_count: u32,
         batch_length: u32,
@@ -112,9 +99,7 @@ impl IggyProducerConfig {
         send_retries_interval: Option<NonZeroIggyDuration>,
     ) -> Self {
         Self {
-            stream_id,
             stream_name,
-            topic_id,
             topic_name,
             topic_partitions_count,
             topic_durability: Durability::default(),
@@ -146,13 +131,12 @@ impl IggyProducerConfig {
         batch_length: u32,
         linger_time: IggyDuration,
     ) -> Result<Self, IggyError> {
-        let stream_id = Identifier::from_str_value(stream)?;
-        let topic_id = Identifier::from_str_value(topic)?;
+        // Validate stream and topic names. Returns IggyError if names are not 
allowed.
+        Identifier::named(stream)?;
+        Identifier::named(topic)?;
 
         Ok(Self {
-            stream_id,
             stream_name: stream.to_string(),
-            topic_id,
             topic_name: topic.to_string(),
             batch_length,
             linger_time,
@@ -167,18 +151,10 @@ impl IggyProducerConfig {
 }
 
 impl IggyProducerConfig {
-    pub fn stream_id(&self) -> &Identifier {
-        &self.stream_id
-    }
-
     pub fn stream_name(&self) -> &str {
         &self.stream_name
     }
 
-    pub fn topic_id(&self) -> &Identifier {
-        &self.topic_id
-    }
-
     pub fn topic_name(&self) -> &str {
         &self.topic_name
     }
@@ -233,9 +209,7 @@ mod tests {
 
         // Builder is generated by the bon macro
         let config = IggyProducerConfig::builder()
-            .stream_id(Identifier::from_str_value(stream).unwrap())
             .stream_name(stream)
-            .topic_id(Identifier::from_str_value(topic).unwrap())
             .topic_name(topic)
             .topic_partitions_count(3)
             .batch_length(100)
@@ -245,15 +219,7 @@ mod tests {
             .send_retries_interval(NonZeroIggyDuration::ONE_SECOND)
             .build();
 
-        assert_eq!(
-            config.stream_id(),
-            &Identifier::from_str_value("test_stream").unwrap()
-        );
         assert_eq!(config.stream_name(), "test_stream");
-        assert_eq!(
-            config.topic_id(),
-            &Identifier::from_str_value("test_topic").unwrap()
-        );
         assert_eq!(config.topic_name(), "test_topic");
         assert_eq!(config.batch_length(), 100);
         assert_eq!(config.linger_time(), 
IggyDuration::from_str("5ms").unwrap());
@@ -268,13 +234,8 @@ mod tests {
 
     #[test]
     fn should_be_default() {
-        let stream_id = Identifier::from_str_value("test_stream").unwrap();
-        let topic_id = Identifier::from_str_value("test_topic").unwrap();
-
         let config = IggyProducerConfig::default();
-        assert_eq!(config.stream_id(), &stream_id);
         assert_eq!(config.stream_name(), "test_stream");
-        assert_eq!(config.topic_id(), &topic_id);
         assert_eq!(config.topic_name(), "test_topic");
         assert_eq!(config.batch_length(), 100);
         assert_eq!(config.linger_time(), 
IggyDuration::from_str("5ms").unwrap());
@@ -289,13 +250,8 @@ mod tests {
 
     #[test]
     fn should_be_new() {
-        let stream_id = Identifier::from_str_value("test_stream").unwrap();
-        let topic_id = Identifier::from_str_value("test_topic").unwrap();
-
         let config = IggyProducerConfig::new(
-            stream_id.clone(),
             String::from("test_stream"),
-            topic_id.clone(),
             String::from("test_topic"),
             3,
             100,
@@ -305,9 +261,7 @@ mod tests {
             None,
             None,
         );
-        assert_eq!(config.stream_id(), &stream_id);
         assert_eq!(config.stream_name(), "test_stream");
-        assert_eq!(config.topic_id(), &topic_id);
         assert_eq!(config.topic_name(), "test_topic");
         assert_eq!(config.batch_length(), 100);
         assert_eq!(config.linger_time(), 
IggyDuration::from_str("5ms").unwrap());
@@ -319,9 +273,6 @@ mod tests {
 
     #[test]
     fn should_be_from_stream_topic() {
-        let stream_id = Identifier::from_str_value("test_stream").unwrap();
-        let topic_id = Identifier::from_str_value("test_topic").unwrap();
-
         let res = IggyProducerConfig::from_stream_topic(
             "test_stream",
             "test_topic",
@@ -332,9 +283,7 @@ mod tests {
         assert!(res.is_ok());
         let config = res.unwrap();
 
-        assert_eq!(config.stream_id(), &stream_id);
         assert_eq!(config.stream_name(), "test_stream");
-        assert_eq!(config.topic_id(), &topic_id);
         assert_eq!(config.topic_name(), "test_topic");
         assert_eq!(config.batch_length(), 100);
         assert_eq!(config.linger_time(), 
IggyDuration::from_str("5ms").unwrap());
diff --git a/core/sdk/src/stream_builder/config/config_iggy_stream.rs 
b/core/sdk/src/stream_builder/config/config_iggy_stream.rs
index 45792e2ba..b3277e76c 100644
--- a/core/sdk/src/stream_builder/config/config_iggy_stream.rs
+++ b/core/sdk/src/stream_builder/config/config_iggy_stream.rs
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use crate::prelude::{Identifier, IggyDuration, IggyError};
+use crate::prelude::{IggyDuration, IggyError};
 use crate::stream_builder::{IggyConsumerConfig, IggyProducerConfig};
 use bon::Builder;
 
@@ -75,9 +75,7 @@ impl IggyStreamConfig {
             producer_config,
         })
     }
-}
 
-impl IggyStreamConfig {
     pub fn consumer_config(&self) -> &IggyConsumerConfig {
         &self.consumer_config
     }
@@ -85,22 +83,6 @@ impl IggyStreamConfig {
     pub fn producer_config(&self) -> &IggyProducerConfig {
         &self.producer_config
     }
-
-    pub fn stream_id(&self) -> &Identifier {
-        self.producer_config.stream_id()
-    }
-
-    pub fn stream_name(&self) -> &str {
-        self.producer_config.stream_name()
-    }
-
-    pub fn topic_id(&self) -> &Identifier {
-        self.producer_config.topic_id()
-    }
-
-    pub fn topic_name(&self) -> &str {
-        self.producer_config.topic_name()
-    }
 }
 
 #[cfg(test)]
@@ -126,8 +108,8 @@ mod tests {
         )
         .unwrap();
         let config = IggyStreamConfig::new(consumer_config, producer_config);
-        assert_eq!(config.stream_name(), "test_stream");
-        assert_eq!(config.topic_name(), "test_topic");
+        assert_eq!(config.consumer_config().stream_name(), "test_stream");
+        assert_eq!(config.producer_config().topic_name(), "test_topic");
         assert_eq!(config.consumer_config().batch_length(), 100);
         assert_eq!(config.producer_config().batch_length(), 100);
         assert_eq!(
@@ -143,8 +125,8 @@ mod tests {
     #[test]
     fn should_be_default() {
         let config = IggyStreamConfig::default();
-        assert_eq!(config.stream_name(), "test_stream");
-        assert_eq!(config.topic_name(), "test_topic");
+        assert_eq!(config.consumer_config().stream_name(), "test_stream");
+        assert_eq!(config.producer_config().topic_name(), "test_topic");
         assert_eq!(config.consumer_config().batch_length(), 100);
         assert_eq!(config.producer_config().batch_length(), 100);
         assert_eq!(
@@ -170,8 +152,8 @@ mod tests {
         assert!(res.is_ok());
         let config = res.unwrap();
 
-        assert_eq!(config.stream_name(), "test_stream");
-        assert_eq!(config.topic_name(), "test_topic");
+        assert_eq!(config.consumer_config().stream_name(), "test_stream");
+        assert_eq!(config.producer_config().topic_name(), "test_topic");
         assert_eq!(config.consumer_config().batch_length(), 100);
         assert_eq!(config.producer_config().batch_length(), 100);
         assert_eq!(
diff --git a/examples/rust/src/shared/system.rs 
b/examples/rust/src/shared/system.rs
index 6f4358e91..c90d2002d 100644
--- a/examples/rust/src/shared/system.rs
+++ b/examples/rust/src/shared/system.rs
@@ -28,8 +28,8 @@ pub async fn init_by_consumer(args: &Args, client: &dyn 
Client) {
         args.partition_id,
     );
     let mut interval = 
tokio::time::interval(std::time::Duration::from_secs(1));
-    let stream_id = stream_id.try_into().unwrap();
-    let topic_id = topic_id.try_into().unwrap();
+    let stream_id = Identifier::named(&stream_id).unwrap();
+    let topic_id = Identifier::named(&topic_id).unwrap();
     loop {
         interval.tick().await;
         info!("Validating if stream: {stream_id} exists..");
@@ -73,7 +73,7 @@ pub async fn init_by_consumer(args: &Args, client: &dyn 
Client) {
 }
 
 pub async fn init_by_producer(args: &Args, client: &dyn Client) -> Result<(), 
IggyError> {
-    let stream_id = args.stream_id.clone().try_into()?;
+    let stream_id = Identifier::named(&args.stream_id)?;
     let topic_name = args.topic_id.clone();
     let stream = client.get_stream(&stream_id).await?;
     if stream.is_some() {
@@ -114,8 +114,8 @@ pub async fn consume_messages(
         interval.map_or("none".to_string(), |i| i.as_human_time_string())
     );
 
-    let stream_id = args.stream_id.clone().try_into()?;
-    let topic_id = args.topic_id.clone().try_into()?;
+    let stream_id = Identifier::named(&args.stream_id)?;
+    let topic_id = Identifier::named(&args.topic_id)?;
     let mut interval = interval.map(|interval| 
tokio::time::interval(interval.get_duration()));
     let mut consumed_batches = 0;
     let consumer = Consumer {
diff --git a/examples/rust/src/stream-builder/stream-basic/main.rs 
b/examples/rust/src/stream-builder/stream-basic/main.rs
index 70edcf49b..08d77048c 100644
--- a/examples/rust/src/stream-builder/stream-basic/main.rs
+++ b/examples/rust/src/stream-builder/stream-basic/main.rs
@@ -61,7 +61,8 @@ async fn main() -> Result<(), IggyError> {
 
     println!("Stop the message stream and shutdown iggy client");
     sender.send(()).expect("Failed to send shutdown signal");
-    client.delete_stream(stream_config.stream_id()).await?;
+    let stream_id = 
Identifier::named(stream_config.producer_config().stream_name())?;
+    client.delete_stream(&stream_id).await?;
     client.shutdown().await?;
 
     Ok(())
diff --git a/examples/rust/src/stream-builder/stream-consumer-config/main.rs 
b/examples/rust/src/stream-builder/stream-consumer-config/main.rs
index ea02ea3db..874c197f0 100644
--- a/examples/rust/src/stream-builder/stream-consumer-config/main.rs
+++ b/examples/rust/src/stream-builder/stream-consumer-config/main.rs
@@ -28,11 +28,9 @@ async fn main() -> Result<(), IggyError> {
     let topic = "test_topic";
 
     let config = IggyConsumerConfig::builder()
-        // Set the stream identifier and name.
-        .stream_id(Identifier::from_str_value(stream)?)
+        // Set the stream name. The consumer binds to the stream by this name.
         .stream_name(stream)
-        // Set the topic identifier and name
-        .topic_id(Identifier::from_str_value(topic)?)
+        // Set the topic name. The consumer binds to the topic by this name.
         .topic_name(topic)
         // The auto-commit configuration for storing the message offset on the 
server.
         // * Disabled:  The auto-commit is disabled and the offset must be 
stored manually by the consumer.
diff --git a/examples/rust/src/stream-builder/stream-producer-config/main.rs 
b/examples/rust/src/stream-builder/stream-producer-config/main.rs
index 00afb7bca..5a34cb08b 100644
--- a/examples/rust/src/stream-builder/stream-producer-config/main.rs
+++ b/examples/rust/src/stream-builder/stream-producer-config/main.rs
@@ -27,11 +27,9 @@ async fn main() -> Result<(), IggyError> {
 
     // The builder simplifies the IggyProducer configuration.
     let config = IggyProducerConfig::builder()
-        // Set the stream identifier and name.
-        .stream_id(Identifier::from_str_value(stream)?)
+        // Set the stream name. The producer binds to the stream by this name.
         .stream_name(stream)
-        // Set the topic identifier and name
-        .topic_id(Identifier::from_str_value(topic)?)
+        // Set the topic name. The producer binds to the topic by this name.
         .topic_name(topic)
         // Sets the number of partitions to create for the topic.
         // The more clients are reading concurrently, the more partitions you 
should create.

Reply via email to