Skip to main content

ahri_tre_protocol/
datastore.rs

1use crate::{
2    ids::PublicUuid,
3    refs::{DatastoreRef, SessionSelector},
4    session::{DatastoreIdentity, SessionStatusPayload},
5};
6use ahri_tre_types::{DatastoreLifecycleState, EncryptionMode, LakeCatalogCredentialMode};
7use serde::{Deserialize, Serialize};
8
9pub const BROWSER_DATASTORE_DISCOVERY_AUTHORITY: &str = "tre_browser.discovery";
10
11#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12pub struct DatastoreInfoRequest {
13    #[serde(default, skip_serializing_if = "Option::is_none")]
14    pub session: Option<SessionSelector>,
15}
16
17#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
18pub struct DatastorePingRequest {
19    #[serde(default, skip_serializing_if = "Option::is_none")]
20    pub session: Option<SessionSelector>,
21}
22
23#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
24pub struct BrowserDatastoreDiscoveryRequest {}
25
26#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
27pub struct BrowserDatastoreDiscoveryRecord {
28    pub datastore_id: PublicUuid,
29    pub datastore: String,
30    pub display_name: String,
31    pub lifecycle_state: DatastoreLifecycleState,
32    pub schema_version: String,
33    pub ready: bool,
34}
35
36#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
37pub struct BrowserDatastoreDiscoveryEmptyState {
38    pub code: String,
39    pub message: String,
40}
41
42#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
43pub struct BrowserDatastoreDiscoveryResponse {
44    pub authority: String,
45    #[serde(default)]
46    pub datastores: Vec<BrowserDatastoreDiscoveryRecord>,
47    #[serde(default, skip_serializing_if = "Option::is_none")]
48    pub empty_state: Option<BrowserDatastoreDiscoveryEmptyState>,
49}
50
51#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
52pub struct DatastoreSummary {
53    pub datastore: DatastoreRef,
54    pub name: String,
55    pub ready: bool,
56}
57
58#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
59pub struct DatastoreDetail {
60    pub summary: DatastoreSummary,
61    #[serde(default, skip_serializing_if = "Option::is_none")]
62    pub metadata_status: Option<ComponentStatus>,
63    #[serde(default, skip_serializing_if = "Option::is_none")]
64    pub lake_status: Option<ComponentStatus>,
65}
66
67#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
68pub struct ComponentStatus {
69    pub ready: bool,
70    #[serde(default, skip_serializing_if = "Option::is_none")]
71    pub message: Option<String>,
72}
73
74#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
75pub struct DatastorePingResult {
76    pub datastore: DatastoreRef,
77    pub metadata: ComponentStatus,
78    pub lake: ComponentStatus,
79}
80
81#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
82pub struct DatastorePingResponse {
83    pub session: SessionStatusPayload,
84    pub datastore: DatastoreRef,
85    pub metadata: ComponentStatus,
86    pub lake: ComponentStatus,
87    #[serde(default, skip_serializing_if = "Option::is_none")]
88    pub binding: Option<DatastoreIdentityBindingStatus>,
89}
90
91#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
92#[serde(rename_all = "snake_case")]
93pub enum DatastoreDiscoveryStatus {
94    Ready,
95    Legacy,
96    Creating,
97    Failed,
98    Retired,
99    Pending,
100    Unsupported,
101    Dirty,
102    TooNew,
103    MissingHistory,
104    Inaccessible,
105}
106
107#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
108pub struct DatastoreIdentityBindingStatus {
109    pub datastore_id: PublicUuid,
110    pub datastore: String,
111    pub ducklake_catalog_database: String,
112    #[serde(default, skip_serializing_if = "Option::is_none")]
113    pub ducklake_catalog_schema: Option<String>,
114    pub lake_path: String,
115    pub ducklake_encryption: bool,
116    pub lake_catalog_credential_mode: LakeCatalogCredentialMode,
117    #[serde(default, skip_serializing_if = "Option::is_none")]
118    pub lake_catalog_role_name: Option<String>,
119    #[serde(default, skip_serializing_if = "Option::is_none")]
120    pub managed_credential_ref: Option<String>,
121    pub credential_version: i32,
122    pub binding_fingerprint: String,
123    pub lifecycle_state: DatastoreLifecycleState,
124    pub verified: bool,
125}
126
127#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
128pub struct MetadataStoreInfo {
129    pub ready: bool,
130    pub database: String,
131    pub user: String,
132    pub server_version: String,
133    pub schema_bootstrapped: bool,
134    pub connection_description: String,
135}
136
137#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
138pub struct LakeInfo {
139    pub ready: bool,
140    pub alias: String,
141    pub catalog_database: String,
142    #[serde(default, skip_serializing_if = "Option::is_none")]
143    pub catalog_schema: Option<String>,
144    pub attach_description: String,
145    pub catalog_type: String,
146    pub extension_version: String,
147    pub configured_encryption_mode: EncryptionMode,
148    pub detected_encryption_mode: EncryptionMode,
149    pub automatic_migration: bool,
150    pub snapshot_count: i64,
151    pub table_count: i64,
152}
153
154#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
155#[serde(rename_all = "snake_case")]
156pub enum DatastoreContentCountStatus {
157    Available,
158    Unsupported,
159    Unavailable,
160}
161
162#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
163pub struct DatastoreContentCount {
164    pub status: DatastoreContentCountStatus,
165    #[serde(default, skip_serializing_if = "Option::is_none")]
166    pub count: Option<u64>,
167}
168
169#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
170pub struct DatastoreContentCounts {
171    pub studies: DatastoreContentCount,
172    pub assets: DatastoreContentCount,
173    pub datasets: DatastoreContentCount,
174    pub datafiles: DatastoreContentCount,
175    pub entities: DatastoreContentCount,
176    pub variables: DatastoreContentCount,
177    pub vocabularies: DatastoreContentCount,
178    pub transformations: DatastoreContentCount,
179}
180
181#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
182pub struct DatastoreInfoResponse {
183    pub session: SessionStatusPayload,
184    pub datastore: DatastoreIdentity,
185    pub metadata_store: MetadataStoreInfo,
186    pub lake: LakeInfo,
187    #[serde(default, skip_serializing_if = "Option::is_none")]
188    pub binding: Option<DatastoreIdentityBindingStatus>,
189    pub content_counts: DatastoreContentCounts,
190}
191
192#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
193pub struct DatastoreSchemaStatusResult {
194    pub datastore: DatastoreRef,
195    pub database: String,
196    pub status: DatastoreSchemaCompatibilityStatus,
197    #[serde(default, skip_serializing_if = "Option::is_none")]
198    pub current_version: Option<String>,
199    pub target_version: String,
200    pub migration_history_present: bool,
201    #[serde(default)]
202    pub applied_versions: Vec<String>,
203    #[serde(default)]
204    pub missing_tables: Vec<String>,
205    pub ducklake_catalog_migrations: DuckLakeCatalogMigrationOwnership,
206}
207
208#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
209pub struct DatastoreMigrationPlanResult {
210    pub status: DatastoreSchemaCompatibilityStatus,
211    #[serde(default, skip_serializing_if = "Option::is_none")]
212    pub current_version: Option<String>,
213    pub target_version: String,
214    #[serde(default)]
215    pub steps: Vec<DatastoreMigrationStepResult>,
216    #[serde(default, skip_serializing_if = "is_false")]
217    pub blocked: bool,
218    #[serde(default, skip_serializing_if = "Option::is_none")]
219    pub blocked_reason: Option<String>,
220    #[serde(default, skip_serializing_if = "Option::is_none")]
221    pub dependency_summary: Option<serde_json::Value>,
222    #[serde(default, skip_serializing_if = "Option::is_none")]
223    pub next_step: Option<String>,
224    pub ducklake_catalog_migrations: DuckLakeCatalogMigrationOwnership,
225}
226
227#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
228pub struct DatastoreMigrationApplyResult {
229    pub before: DatastoreMigrationPlanResult,
230    pub after: DatastoreSchemaStatusResult,
231    #[serde(default)]
232    pub applied_steps: Vec<DatastoreMigrationStepResult>,
233    #[serde(default, skip_serializing_if = "is_false")]
234    pub blocked: bool,
235    #[serde(default, skip_serializing_if = "Option::is_none")]
236    pub blocked_reason: Option<String>,
237    #[serde(default, skip_serializing_if = "Option::is_none")]
238    pub dependency_summary: Option<serde_json::Value>,
239    #[serde(default, skip_serializing_if = "Option::is_none")]
240    pub next_step: Option<String>,
241}
242
243const fn is_false(value: &bool) -> bool {
244    !*value
245}
246
247#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
248pub struct DatastoreMigrationStepResult {
249    pub version: String,
250    pub description: String,
251    pub scope: DatastoreMigrationScope,
252    pub transactional: bool,
253    pub action: DatastoreMigrationAction,
254}
255
256#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
257#[serde(rename_all = "snake_case")]
258pub enum DatastoreMigrationScope {
259    Metadata,
260}
261
262#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
263#[serde(rename_all = "snake_case")]
264pub enum DatastoreMigrationAction {
265    Apply,
266    Skipped,
267    Failed,
268    Blocked,
269}
270
271#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
272#[serde(rename_all = "snake_case")]
273pub enum DatastoreSchemaCompatibilityStatus {
274    Current,
275    Pending,
276    MissingHistory,
277    Dirty,
278    TooNew,
279    Unsupported,
280}
281
282#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
283pub struct DuckLakeCatalogMigrationOwnership {
284    pub database: String,
285    #[serde(default, skip_serializing_if = "Option::is_none")]
286    pub schema: Option<String>,
287    pub managed_by: String,
288    pub included_in_datastore_schema_migration: bool,
289}