radixdb_api/
application.rs1use chrono::{DateTime, Duration, Utc};
15use radixdb_core::Result;
16
17pub use radixdb_executor::application::{
18 ApplicationRelationIdentity, ApplicationRetentionOutcome, ApplicationRetentionPolicy,
19 AuditEvent, ObjectId, OutboxClaim, OutboxCompletion, OutboxMessage, OutboxRetryDisposition,
20 AUDIT_RELATION_NAME, OUTBOX_RELATION_NAME,
21};
22use radixdb_executor::context::ExecutionContext;
23
24use crate::{Database, Transaction};
25
26impl Database {
27 pub fn install_application_relations(&self) -> Result<ApplicationRelationIdentity> {
30 self.with_connection_executor(|executor| executor.install_application_relations())
31 }
32
33 pub fn application_relation_identity(&self) -> Result<ApplicationRelationIdentity> {
35 self.with_connection_executor(|executor| executor.application_relation_identity())
36 }
37
38 pub fn claim_outbox(
41 &self,
42 worker_id: &str,
43 now: DateTime<Utc>,
44 lease_duration: Duration,
45 limit: usize,
46 max_attempts: u32,
47 ) -> Result<Vec<OutboxClaim>> {
48 self.with_connection_executor(|executor| {
49 executor.claim_outbox(worker_id, now, lease_duration, limit, max_attempts)
50 })
51 }
52
53 pub fn complete_outbox(
55 &self,
56 message_id: [u8; 16],
57 lease_token: [u8; 16],
58 completed_at: DateTime<Utc>,
59 ) -> Result<OutboxCompletion> {
60 self.with_connection_executor(|executor| {
61 executor.complete_outbox(message_id, lease_token, completed_at)
62 })
63 }
64
65 pub fn retry_outbox(
68 &self,
69 message_id: [u8; 16],
70 lease_token: [u8; 16],
71 failed_at: DateTime<Utc>,
72 retry_at: DateTime<Utc>,
73 error: &str,
74 max_attempts: u32,
75 ) -> Result<OutboxRetryDisposition> {
76 self.with_connection_executor(|executor| {
77 executor.retry_outbox(
78 message_id,
79 lease_token,
80 failed_at,
81 retry_at,
82 error,
83 max_attempts,
84 )
85 })
86 }
87
88 pub fn prune_application_history(
91 &self,
92 now: DateTime<Utc>,
93 policy: ApplicationRetentionPolicy,
94 ) -> Result<ApplicationRetentionOutcome> {
95 self.with_connection_executor(|executor| executor.prune_application_history(now, policy))
96 }
97}
98
99impl Transaction {
100 pub fn append_audit_event(&mut self, event: AuditEvent) -> Result<[u8; 16]> {
104 self.check_active()?;
105 self.executor()
106 .append_audit_event(&ExecutionContext::new(), event)
107 }
108
109 pub fn append_outbox_message(&mut self, message: OutboxMessage) -> Result<[u8; 16]> {
111 self.check_active()?;
112 self.executor().append_outbox_message(message)
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use radixdb_core::Value;
119
120 use super::*;
121
122 #[test]
123 fn public_facade_keeps_business_audit_and_outbox_in_one_transaction() {
124 let database = Database::open_in_memory().unwrap();
125 database.install_application_relations().unwrap();
126 database
127 .execute("CREATE TABLE business_record (id INTEGER PRIMARY KEY)", ())
128 .unwrap();
129
130 let mut transaction = database.begin().unwrap();
131 transaction
132 .execute("INSERT INTO business_record VALUES (1)", ())
133 .unwrap();
134 transaction
135 .append_audit_event(AuditEvent {
136 object_id: ObjectId::BOOTSTRAP_NAMESPACE,
137 command_fingerprint: [3; 32],
138 metadata: Value::json(r#"{"operation":"create"}"#),
139 })
140 .unwrap();
141 transaction
142 .append_outbox_message(OutboxMessage {
143 idempotency_key: "business-record-1".to_owned(),
144 schema_version: 1,
145 payload: Value::json(r#"{"id":1}"#),
146 })
147 .unwrap();
148 transaction.commit().unwrap();
149
150 assert_eq!(
151 database
152 .query_one::<i64, _>("SELECT COUNT(*) FROM business_record", ())
153 .unwrap(),
154 1
155 );
156 assert_eq!(
157 database
158 .query_one::<i64, _>("SELECT COUNT(*) FROM audit.event", ())
159 .unwrap(),
160 1
161 );
162 assert_eq!(
163 database
164 .query_one::<i64, _>("SELECT COUNT(*) FROM outbox.message", ())
165 .unwrap(),
166 1
167 );
168 }
169}