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}