pub struct AsyncUmaDbClient { /* private fields */ }Implementations§
Source§impl AsyncUmaDbClient
impl AsyncUmaDbClient
pub async fn connect( url: String, ca_path: Option<String>, batch_size: Option<u32>, api_key: Option<String>, ) -> DcbResult<Self>
Sourcepub async fn subscribe(
&self,
query: Option<DcbQuery>,
after: Option<u64>,
) -> DcbResult<Box<dyn DcbSubscriptionAsync + Send + 'static>>
pub async fn subscribe( &self, query: Option<DcbQuery>, after: Option<u64>, ) -> DcbResult<Box<dyn DcbSubscriptionAsync + Send + 'static>>
Examples found in repository?
examples/client_async_insecure.rs (line 104)
10async fn main() -> Result<(), Box<dyn std::error::Error>> {
11 // Connect to the gRPC server
12 let url = "http://localhost:50051".to_string();
13 let client = UmaDbClient::new(url).connect_async().await?;
14
15 // Define a consistency boundary
16 let boundary = DcbQuery::new().item(
17 DcbQueryItem::new()
18 .types(["example"])
19 .tags(["tag1", "tag2"]),
20 );
21
22 // Read events for a decision model
23 let mut read_response = client
24 .read(Some(boundary.clone()), None, false, None)
25 .await?;
26
27 // Build decision model
28 while let Some(result) = read_response.next().await {
29 match result {
30 Ok(event) => {
31 println!(
32 "Got event at position {}: {:?}",
33 event.position, event.event
34 );
35 }
36 Err(status) => panic!("gRPC stream error: {}", status),
37 }
38 }
39
40 // Remember the last-known position
41 let last_known_position = read_response.head().await?;
42 println!("Last known position is: {:?}", last_known_position);
43
44 // Produce new event, attaching some metadata (e.g. provenance) that is
45 // stored alongside the event and returned when it is read back.
46 let event = DcbEvent::default()
47 .event_type("example")
48 .tags(["tag1", "tag2"])
49 .data(b"Hello, world!")
50 .uuid(Uuid::new_v4())
51 .metadata_entry("source", "client_async_insecure")
52 .metadata_entry("correlation_id", Uuid::new_v4().to_string());
53
54 // Append event in consistency boundary
55 let append_condition = DcbAppendCondition {
56 fail_if_events_match: boundary.clone(),
57 after: last_known_position,
58 };
59 let position1 = client
60 .append(vec![event.clone()], Some(append_condition.clone()), None)
61 .await?;
62
63 println!("Appended event at position: {}", position1);
64
65 // Append conflicting event - expect an error
66 let conflicting_event = DcbEvent::default()
67 .event_type("example")
68 .tags(["tag1", "tag2"])
69 .data(b"Hello, world!")
70 .uuid(Uuid::new_v4()); // different UUID
71
72 let conflicting_result = client
73 .append(
74 vec![conflicting_event.clone()],
75 Some(append_condition.clone()),
76 None,
77 )
78 .await;
79
80 // Expect an integrity error
81 match conflicting_result {
82 Err(DcbError::IntegrityError(integrity_error)) => {
83 println!("Conflicting event was rejected: {:?}", integrity_error);
84 }
85 other => panic!("Expected IntegrityError, got {:?}", other),
86 }
87
88 // Appending with identical events IDs and append conditions is idempotent.
89 println!(
90 "Retrying to append event at position: {:?}",
91 last_known_position
92 );
93 let position2 = client
94 .append(vec![event.clone()], Some(append_condition.clone()), None)
95 .await?;
96
97 if position1 == position2 {
98 println!("Append method returned same commit position: {}", position2);
99 } else {
100 panic!("Expected idempotent retry!")
101 }
102
103 // Subscribe to all events for a projection
104 let mut subscription = client.subscribe(None, None).await?;
105
106 // Build an up-to-date view
107 while let Some(result) = subscription.next().await {
108 match result {
109 Ok(ev) => {
110 println!("Processing event at {}: {:?}", ev.position, ev.event);
111 if ev.position == position2 {
112 println!("Projection has processed new event!");
113 break;
114 }
115 }
116 Err(status) => panic!("gRPC stream error: {}", status),
117 }
118 }
119
120 // Track an upstream position
121 let upstream_position = client.get_tracking_info("upstream").await?;
122 let next_upstream_position = upstream_position.unwrap_or(0) + 1;
123 println!("Next upstream position: {next_upstream_position}");
124 client
125 .append(
126 vec![],
127 None,
128 Some(TrackingInfo {
129 source: "upstream".to_string(),
130 position: next_upstream_position,
131 }),
132 )
133 .await?;
134 assert_eq!(
135 next_upstream_position,
136 client.get_tracking_info("upstream").await?.unwrap()
137 );
138 println!("Upstream position tracked okay!");
139
140 // Try recording the same upstream position
141 let conflicting_result = client
142 .append(
143 vec![],
144 None,
145 Some(TrackingInfo {
146 source: "upstream".to_string(),
147 position: next_upstream_position,
148 }),
149 )
150 .await;
151
152 // Expect an integrity error
153 match conflicting_result {
154 Err(DcbError::IntegrityError(integrity_error)) => {
155 println!(
156 "Conflicting upstream position was rejected: {:?}",
157 integrity_error
158 );
159 }
160 other => panic!("Expected IntegrityError, got {:?}", other),
161 }
162
163 Ok(())
164}More examples
examples/client_async_secure.rs (line 126)
10async fn main() -> Result<(), Box<dyn std::error::Error>> {
11 // Connect to the gRPC server
12 let url = "https://localhost:50051".to_string();
13 let client = UmaDbClient::new(url)
14 .ca_path("server.pem".to_string()) // For self-signed server certificates.
15 .api_key("umadb:example-api-key-4f7c2b1d9e5f4a038c1a".to_string())
16 .connect_async()
17 .await?;
18
19 // Define a consistency boundary
20 let cb = DcbQuery {
21 items: vec![DcbQueryItem {
22 types: vec!["example".to_string()],
23 tags: vec!["tag1".to_string(), "tag2".to_string()],
24 }],
25 };
26
27 // Read events for a decision model
28 let mut read_response = client.read(Some(cb.clone()), None, false, None).await?;
29
30 // Build decision model
31 while let Some(result) = read_response.next().await {
32 match result {
33 Ok(event) => {
34 println!(
35 "Got event at position {}: {:?}",
36 event.position, event.event
37 );
38 }
39 Err(status) => panic!("gRPC stream error: {}", status),
40 }
41 }
42
43 // Remember the last-known position
44 let last_known_position = read_response.head().await?;
45 println!("Last known position is: {:?}", last_known_position);
46
47 // Produce new event, attaching some metadata (e.g. provenance) that is
48 // stored alongside the event and returned when it is read back.
49 let mut metadata = Vec::new();
50 metadata.push(("source".to_string(), "client_async_secure".to_string()));
51 metadata.push(("correlation_id".to_string(), Uuid::new_v4().to_string()));
52 let event = DcbEvent {
53 event_type: "example".to_string(),
54 tags: vec!["tag1".to_string(), "tag2".to_string()],
55 data: b"Hello, world!".to_vec(),
56 uuid: Some(Uuid::new_v4()),
57 metadata,
58 };
59
60 // Append event in consistency boundary
61 let commit_position1 = client
62 .append(
63 vec![event.clone()],
64 Some(DcbAppendCondition {
65 fail_if_events_match: cb.clone(),
66 after: last_known_position,
67 }),
68 None,
69 )
70 .await?;
71 println!("Appended event at position: {}", commit_position1);
72
73 // Append conflicting event - expect an error
74 let conflicting_event = DcbEvent {
75 event_type: "example".to_string(),
76 tags: vec!["tag1".to_string(), "tag2".to_string()],
77 data: b"Hello, world!".to_vec(),
78 uuid: Some(Uuid::new_v4()), // different UUID
79 metadata: Vec::new(),
80 };
81 let conflicting_result = client
82 .append(
83 vec![conflicting_event.clone()],
84 Some(DcbAppendCondition {
85 fail_if_events_match: cb.clone(),
86 after: last_known_position,
87 }),
88 None,
89 )
90 .await;
91
92 // Expect an integrity error
93 match conflicting_result {
94 Err(DcbError::IntegrityError(integrity_error)) => {
95 println!("Conflicting event was rejected: {:?}", integrity_error);
96 }
97 other => panic!("Expected IntegrityError, got {:?}", other),
98 }
99
100 // Conditional appends with event UUIDs are idempotent.
101 println!(
102 "Retrying to append event at position: {:?}",
103 last_known_position
104 );
105 let commit_position2 = client
106 .append(
107 vec![event.clone()],
108 Some(DcbAppendCondition {
109 fail_if_events_match: cb.clone(),
110 after: last_known_position,
111 }),
112 None,
113 )
114 .await?;
115
116 if commit_position1 == commit_position2 {
117 println!(
118 "Append method returned same commit position: {}",
119 commit_position2
120 );
121 } else {
122 panic!("Expected idempotent retry!")
123 }
124
125 // Subscribe to all events for a projection
126 let mut subscription = client.subscribe(None, None).await?;
127
128 // Build an up-to-date view
129 while let Some(result) = subscription.next().await {
130 match result {
131 Ok(ev) => {
132 println!("Processing event at {}: {:?}", ev.position, ev.event);
133 if ev.position == commit_position2 {
134 println!("Projection has processed new event!");
135 break;
136 }
137 }
138 Err(status) => panic!("gRPC stream error: {}", status),
139 }
140 }
141
142 // Track an upstream position
143 let upstream_position = client.get_tracking_info("upstream").await?;
144 let next_upstream_position = upstream_position.unwrap_or(0) + 1;
145 println!("Next upstream position: {next_upstream_position}");
146 client
147 .append(
148 vec![],
149 None,
150 Some(TrackingInfo {
151 source: "upstream".to_string(),
152 position: next_upstream_position,
153 }),
154 )
155 .await?;
156 assert_eq!(
157 next_upstream_position,
158 client.get_tracking_info("upstream").await?.unwrap()
159 );
160 println!("Upstream position tracked okay!");
161
162 // Try recording the same upstream position
163 let conflicting_result = client
164 .append(
165 vec![],
166 None,
167 Some(TrackingInfo {
168 source: "upstream".to_string(),
169 position: next_upstream_position,
170 }),
171 )
172 .await;
173
174 // Expect an integrity error
175 match conflicting_result {
176 Err(DcbError::IntegrityError(integrity_error)) => {
177 println!(
178 "Conflicting upstream position was rejected: {:?}",
179 integrity_error
180 );
181 }
182 other => panic!("Expected IntegrityError, got {:?}", other),
183 }
184
185 Ok(())
186}Sourcepub fn close(&self)
pub fn close(&self)
Stops all streaming responses opened by this client.
This affects only streams opened via this client instance’s read() and
subscribe() methods; it does not stop or otherwise affect the server, nor
streams opened by other clients.
pub async fn connect_with_tls_options( url: String, tls_options: Option<ClientTlsOptions>, batch_size: Option<u32>, api_key: Option<String>, ) -> DcbResult<Self>
Trait Implementations§
Source§impl DcbEventStoreAsync for AsyncUmaDbClient
impl DcbEventStoreAsync for AsyncUmaDbClient
Source§fn read<'a, 'async_trait>(
&'a self,
query: Option<DcbQuery>,
start: Option<u64>,
backwards: bool,
limit: Option<u32>,
) -> Pin<Box<dyn Future<Output = DcbResult<Box<dyn DcbReadResponseAsync + Send + 'static>>> + Send + 'async_trait>>where
Self: 'async_trait,
'a: 'async_trait,
fn read<'a, 'async_trait>(
&'a self,
query: Option<DcbQuery>,
start: Option<u64>,
backwards: bool,
limit: Option<u32>,
) -> Pin<Box<dyn Future<Output = DcbResult<Box<dyn DcbReadResponseAsync + Send + 'static>>> + Send + 'async_trait>>where
Self: 'async_trait,
'a: 'async_trait,
Reads events from the store based on the provided query and constraints Read more
Source§fn head<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = DcbResult<Option<u64>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn head<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = DcbResult<Option<u64>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Returns the current head position of the event store, or None if empty Read more
Source§fn get_tracking_info<'life0, 'life1, 'async_trait>(
&'life0 self,
source: &'life1 str,
) -> Pin<Box<dyn Future<Output = DcbResult<Option<u64>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn get_tracking_info<'life0, 'life1, 'async_trait>(
&'life0 self,
source: &'life1 str,
) -> Pin<Box<dyn Future<Output = DcbResult<Option<u64>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Returns the greatest recorded upstream position for a tracking source, if any
Source§fn append<'life0, 'async_trait>(
&'life0 self,
events: Vec<DcbEvent>,
condition: Option<DcbAppendCondition>,
tracking_info: Option<TrackingInfo>,
) -> Pin<Box<dyn Future<Output = DcbResult<u64>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn append<'life0, 'async_trait>(
&'life0 self,
events: Vec<DcbEvent>,
condition: Option<DcbAppendCondition>,
tracking_info: Option<TrackingInfo>,
) -> Pin<Box<dyn Future<Output = DcbResult<u64>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Appends given events to the event store, unless the condition fails Read more
Source§fn read_with_head<'a, 'async_trait>(
&'a self,
query: Option<DcbQuery>,
after: Option<u64>,
backwards: bool,
limit: Option<u32>,
) -> Pin<Box<dyn Future<Output = Result<(Vec<DcbSequencedEvent>, Option<u64>), DcbError>> + Send + 'async_trait>>where
'a: 'async_trait,
Self: 'async_trait,
fn read_with_head<'a, 'async_trait>(
&'a self,
query: Option<DcbQuery>,
after: Option<u64>,
backwards: bool,
limit: Option<u32>,
) -> Pin<Box<dyn Future<Output = Result<(Vec<DcbSequencedEvent>, Option<u64>), DcbError>> + Send + 'async_trait>>where
'a: 'async_trait,
Self: 'async_trait,
Reads events from the store and returns them as a tuple of
(Vec<DcbSequencedEvent>, Option<u64>)Source§impl Drop for AsyncUmaDbClient
impl Drop for AsyncUmaDbClient
Auto Trait Implementations§
impl !Freeze for AsyncUmaDbClient
impl !RefUnwindSafe for AsyncUmaDbClient
impl !UnwindSafe for AsyncUmaDbClient
impl Send for AsyncUmaDbClient
impl Sync for AsyncUmaDbClient
impl Unpin for AsyncUmaDbClient
impl UnsafeUnpin for AsyncUmaDbClient
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
Wrap the input message
T in a tonic::Request