1use crate::{
2 ProtocolVersion, PublicName,
3 domain::DomainSelector,
4 pagination::PageRequest,
5 public_error::{ProtocolError, ValidationIssue, ValidationIssueCode},
6 refs::{DomainRef, EntityRef, RelationRef, SessionSelector, TagSummary},
7 search::{PredicateSet, SearchCursorBinding, TagPredicate, TextPredicate},
8};
9use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12#[serde(tag = "kind", rename_all = "snake_case")]
13pub enum EntitySelector {
14 Id {
15 entity: EntityRef,
16 #[serde(default, skip_serializing_if = "Option::is_none")]
17 domain: Option<DomainSelector>,
18 },
19 Name {
20 domain: DomainSelector,
21 name: PublicName,
22 },
23}
24
25#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
26#[serde(tag = "kind", rename_all = "snake_case")]
27pub enum RelationSelector {
28 Id {
29 relation: RelationRef,
30 #[serde(default, skip_serializing_if = "Option::is_none")]
31 domain: Option<DomainSelector>,
32 },
33 Name {
34 domain: DomainSelector,
35 name: PublicName,
36 },
37}
38
39#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
40pub struct EntitySummary {
41 pub entity: EntityRef,
42 pub domain: DomainRef,
43 pub name: String,
44 #[serde(default, skip_serializing_if = "Option::is_none")]
45 pub description: Option<String>,
46 #[serde(default, skip_serializing_if = "Option::is_none")]
47 pub ontology_class: Option<String>,
48 #[serde(default)]
49 pub tags: Vec<TagSummary>,
50}
51
52#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
53pub struct EntityDetail {
54 pub summary: EntitySummary,
55 #[serde(default, skip_serializing_if = "Option::is_none")]
56 pub agent_instructions: Option<String>,
57 #[serde(default, skip_serializing_if = "Option::is_none")]
58 pub ontology_namespace: Option<String>,
59}
60
61#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
62pub struct RelationDefinitionSummary {
63 pub relation: RelationRef,
64 pub domain: DomainRef,
65 pub name: String,
66 pub subject_entity: EntityRef,
67 pub object_entity: EntityRef,
68 #[serde(default, skip_serializing_if = "Option::is_none")]
69 pub subject_entity_name: Option<String>,
70 #[serde(default, skip_serializing_if = "Option::is_none")]
71 pub object_entity_name: Option<String>,
72 #[serde(default, skip_serializing_if = "Option::is_none")]
73 pub description: Option<String>,
74 #[serde(default, skip_serializing_if = "Option::is_none")]
75 pub ontology_class: Option<String>,
76 #[serde(default)]
77 pub tags: Vec<TagSummary>,
78}
79
80#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
81pub struct RelationDefinitionDetail {
82 pub summary: RelationDefinitionSummary,
83 #[serde(default, skip_serializing_if = "Option::is_none")]
84 pub agent_instructions: Option<String>,
85 #[serde(default, skip_serializing_if = "Option::is_none")]
86 pub ontology_namespace: Option<String>,
87}
88
89pub type EntityInstanceSummary = SemanticInstanceReadback;
90
91pub type RelationInstanceSummary = SemanticInstanceReadback;
92
93pub type ModelMappingSummary = SemanticMappingReadback;
94
95pub type ModelLinkSummary = SemanticLinkIdentity;
96
97#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
98pub struct ModelWarnings {
99 #[serde(default, skip_serializing_if = "Vec::is_empty")]
100 pub warnings: Vec<String>,
101 #[serde(default, skip_serializing_if = "Vec::is_empty")]
102 pub validation_errors: Vec<String>,
103}
104
105#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
106pub struct ModelMutationIntent {
107 #[serde(default)]
108 pub force_update: bool,
109 #[serde(default)]
110 pub check_dependencies: bool,
111}
112
113#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
114pub struct RelationSummary {
115 pub relation: RelationRef,
116 pub domain: DomainRef,
117 pub name: String,
118 pub source_entity: EntityRef,
119 pub source_entity_name: String,
120 pub target_entity: EntityRef,
121 pub target_entity_name: String,
122 #[serde(default, skip_serializing_if = "Option::is_none")]
123 pub description: Option<String>,
124 #[serde(default, skip_serializing_if = "Option::is_none")]
125 pub ontology_class: Option<String>,
126 #[serde(default)]
127 pub tags: Vec<TagSummary>,
128}
129
130#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
131pub struct SearchEntitiesRequest {
132 #[serde(default, skip_serializing_if = "Option::is_none")]
133 pub session: Option<SessionSelector>,
134 pub predicates: PredicateSet<EntityPredicate>,
135 pub page: PageRequest,
136}
137
138#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
140pub struct BrowserEntitySearchRequest {
141 pub datastore_id: crate::PublicUuid,
142 pub search: SearchEntitiesRequest,
143}
144
145#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
146pub struct EntitySearchCursorAnchor {
147 pub domain: DomainRef,
148 pub entity: EntityRef,
149 pub name: String,
150}
151
152#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
153pub struct EntitySearchCursorQuery {
154 pub predicates: PredicateSet<EntityPredicate>,
155}
156
157#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
158pub struct EntitySearchCursor {
159 pub binding: SearchCursorBinding<EntitySearchCursorQuery>,
160 pub after: EntitySearchCursorAnchor,
161}
162
163#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
165pub struct BrowserEntitySearchResponse {
166 pub protocol_version: ProtocolVersion,
167 pub datastore_id: crate::PublicUuid,
168 pub family: String,
169 pub predicates: PredicateSet<EntityPredicate>,
170 #[serde(default)]
171 pub entities: Vec<crate::semantic_discovery::BrowserEntityDiscoveryRecord>,
172 pub returned_count: u16,
173 pub requested_limit: u16,
174 pub ordering: crate::study::BrowserSearchOrdering,
175 pub has_more: bool,
176 #[serde(default, skip_serializing_if = "Option::is_none")]
177 pub next_cursor: Option<String>,
178 #[serde(default, skip_serializing_if = "Option::is_none")]
179 pub empty_state: Option<BrowserEntitySearchEmptyState>,
180}
181
182#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
183pub struct BrowserEntitySearchEmptyState {
184 pub code: String,
185 pub message: String,
186}
187
188#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
189pub struct BrowserEntitySearchCursorQuery {
190 pub datastore_id: crate::PublicUuid,
191 pub family: String,
192 pub predicates: PredicateSet<EntityPredicate>,
193}
194
195#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
196pub struct BrowserEntitySearchCursor {
197 pub binding: SearchCursorBinding<BrowserEntitySearchCursorQuery>,
198 pub after: EntitySearchCursorAnchor,
199}
200
201#[allow(clippy::result_large_err)]
202impl SearchEntitiesRequest {
203 #[allow(clippy::result_large_err)]
204 pub fn validate_for_browser(
205 &mut self,
206 datastore_id: crate::PublicUuid,
207 protocol_version: &ProtocolVersion,
208 ) -> Result<(), ProtocolError> {
209 let mut issues = Vec::new();
210 collect_entity_predicate_set_issues("body.predicates", &self.predicates, &mut issues);
211 collect_entity_predicate_issues(&mut self.predicates, &mut issues);
212 if let Err(message) = self.page.validate() {
213 issues.push(ValidationIssue::new(
214 "body.page.limit",
215 ValidationIssueCode::OutOfRange,
216 message,
217 ));
218 }
219 if let Some(raw_cursor) = self.page.cursor.as_deref() {
220 match serde_json::from_str::<BrowserEntitySearchCursor>(raw_cursor) {
221 Ok(cursor) if cursor.binding == self.browser_cursor_binding(datastore_id, protocol_version) => {}
222 Ok(_) => issues.push(ValidationIssue::new("body.page.cursor", ValidationIssueCode::Conflict, "browser model-entity search cursor does not match the datastore, search family, predicates, page limit, or protocol version")),
223 Err(_) => issues.push(ValidationIssue::new("body.page.cursor", ValidationIssueCode::InvalidFormat, "browser model-entity search cursor is invalid")),
224 }
225 }
226 if issues.is_empty() {
227 Ok(())
228 } else {
229 Err(ProtocolError::validation(
230 "browser model-entity search request is invalid",
231 issues,
232 ))
233 }
234 }
235
236 #[allow(clippy::result_large_err)]
237 pub fn browser_decoded_cursor(
238 &self,
239 datastore_id: crate::PublicUuid,
240 protocol_version: &ProtocolVersion,
241 ) -> Result<Option<EntitySearchCursorAnchor>, ProtocolError> {
242 let Some(raw_cursor) = self.page.cursor.as_deref() else {
243 return Ok(None);
244 };
245 let cursor: BrowserEntitySearchCursor = serde_json::from_str(raw_cursor).map_err(|_| {
246 ProtocolError::validation(
247 "browser model-entity search request is invalid",
248 vec![ValidationIssue::new(
249 "body.page.cursor",
250 ValidationIssueCode::InvalidFormat,
251 "browser model-entity search cursor is invalid",
252 )],
253 )
254 })?;
255 if cursor.binding != self.browser_cursor_binding(datastore_id, protocol_version) {
256 return Err(ProtocolError::validation(
257 "browser model-entity search request is invalid",
258 vec![ValidationIssue::new(
259 "body.page.cursor",
260 ValidationIssueCode::Conflict,
261 "browser model-entity search cursor does not match the datastore, search family, predicates, page limit, or protocol version",
262 )],
263 ));
264 }
265 Ok(Some(cursor.after))
266 }
267
268 #[allow(clippy::result_large_err)]
269 pub fn encode_browser_cursor(
270 &self,
271 datastore_id: crate::PublicUuid,
272 protocol_version: &ProtocolVersion,
273 after: EntitySearchCursorAnchor,
274 ) -> Result<String, ProtocolError> {
275 serde_json::to_string(&BrowserEntitySearchCursor {
276 binding: self.browser_cursor_binding(datastore_id, protocol_version),
277 after,
278 })
279 .map_err(|error| {
280 ProtocolError::new(
281 crate::public_error::ProtocolErrorCode::Internal,
282 format!("failed to encode browser entity search cursor: {error}"),
283 )
284 })
285 }
286
287 fn browser_cursor_binding(
288 &self,
289 datastore_id: crate::PublicUuid,
290 protocol_version: &ProtocolVersion,
291 ) -> SearchCursorBinding<BrowserEntitySearchCursorQuery> {
292 SearchCursorBinding {
293 query: BrowserEntitySearchCursorQuery {
294 datastore_id,
295 family: "model_entities".to_string(),
296 predicates: self.predicates.clone(),
297 },
298 page_limit: self.page.limit,
299 protocol_version: protocol_version.to_string(),
300 }
301 }
302 pub fn validate(&mut self, protocol_version: &ProtocolVersion) -> Result<(), ProtocolError> {
303 let mut issues = Vec::new();
304 collect_entity_predicate_set_issues("body.predicates", &self.predicates, &mut issues);
305 collect_entity_predicate_issues(&mut self.predicates, &mut issues);
306 if let Err(message) = self.page.validate() {
307 issues.push(ValidationIssue::new(
308 "body.page.limit",
309 ValidationIssueCode::OutOfRange,
310 message,
311 ));
312 }
313 collect_entity_cursor_issues(self, protocol_version, &mut issues);
314
315 if issues.is_empty() {
316 Ok(())
317 } else {
318 Err(ProtocolError::validation(
319 "entity search request is invalid",
320 issues,
321 ))
322 }
323 }
324
325 pub fn decoded_cursor(
326 &self,
327 protocol_version: &ProtocolVersion,
328 ) -> Result<Option<EntitySearchCursorAnchor>, ProtocolError> {
329 match self.page.cursor.as_deref() {
330 None => Ok(None),
331 Some(raw_cursor) => {
332 let cursor: EntitySearchCursor =
333 serde_json::from_str(raw_cursor).map_err(|error| {
334 ProtocolError::validation(
335 "entity search request is invalid",
336 vec![ValidationIssue::new(
337 "body.page.cursor",
338 ValidationIssueCode::InvalidFormat,
339 format!("entity search cursor is invalid: {error}"),
340 )],
341 )
342 })?;
343 let expected = self.cursor_binding(protocol_version);
344 if cursor.binding != expected {
345 return Err(ProtocolError::validation(
346 "entity search request is invalid",
347 vec![ValidationIssue::new(
348 "body.page.cursor",
349 ValidationIssueCode::Conflict,
350 "entity search cursor does not match the request predicates, page limit, or protocol version",
351 )],
352 ));
353 }
354 Ok(Some(cursor.after))
355 }
356 }
357 }
358
359 pub fn encode_cursor(
360 &self,
361 protocol_version: &ProtocolVersion,
362 after: EntitySearchCursorAnchor,
363 ) -> Result<String, ProtocolError> {
364 serde_json::to_string(&EntitySearchCursor {
365 binding: self.cursor_binding(protocol_version),
366 after,
367 })
368 .map_err(|error| {
369 ProtocolError::new(
370 crate::public_error::ProtocolErrorCode::Internal,
371 format!("failed to encode entity search cursor: {error}"),
372 )
373 })
374 }
375
376 fn cursor_binding(
377 &self,
378 protocol_version: &ProtocolVersion,
379 ) -> SearchCursorBinding<EntitySearchCursorQuery> {
380 SearchCursorBinding {
381 query: EntitySearchCursorQuery {
382 predicates: self.predicates.clone(),
383 },
384 page_limit: self.page.limit,
385 protocol_version: protocol_version.to_string(),
386 }
387 }
388}
389
390#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
391pub struct SearchRelationsRequest {
392 #[serde(default, skip_serializing_if = "Option::is_none")]
393 pub session: Option<SessionSelector>,
394 pub predicates: PredicateSet<RelationPredicate>,
395 pub page: PageRequest,
396}
397
398#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
400pub struct BrowserRelationSearchRequest {
401 pub datastore_id: crate::PublicUuid,
402 pub search: SearchRelationsRequest,
403}
404
405#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
406pub struct RelationSearchCursorAnchor {
407 pub domain: DomainRef,
408 pub relation: RelationRef,
409 pub name: String,
410}
411
412#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
413pub struct RelationSearchCursorQuery {
414 pub predicates: PredicateSet<RelationPredicate>,
415}
416
417#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
418pub struct RelationSearchCursor {
419 pub binding: SearchCursorBinding<RelationSearchCursorQuery>,
420 pub after: RelationSearchCursorAnchor,
421}
422
423#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
425pub struct BrowserRelationSearchResponse {
426 pub protocol_version: ProtocolVersion,
427 pub datastore_id: crate::PublicUuid,
428 pub family: String,
429 pub predicates: PredicateSet<RelationPredicate>,
430 #[serde(default)]
431 pub relations: Vec<crate::semantic_discovery::BrowserEntityRelationDiscoveryRecord>,
432 pub returned_count: u16,
433 pub requested_limit: u16,
434 pub ordering: crate::study::BrowserSearchOrdering,
435 pub has_more: bool,
436 #[serde(default, skip_serializing_if = "Option::is_none")]
437 pub next_cursor: Option<String>,
438 #[serde(default, skip_serializing_if = "Option::is_none")]
439 pub empty_state: Option<BrowserRelationSearchEmptyState>,
440}
441
442#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
443pub struct BrowserRelationSearchEmptyState {
444 pub code: String,
445 pub message: String,
446}
447
448#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
449pub struct BrowserRelationSearchCursorQuery {
450 pub datastore_id: crate::PublicUuid,
451 pub family: String,
452 pub predicates: PredicateSet<RelationPredicate>,
453}
454
455#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
456pub struct BrowserRelationSearchCursor {
457 pub binding: SearchCursorBinding<BrowserRelationSearchCursorQuery>,
458 pub after: RelationSearchCursorAnchor,
459}
460
461#[allow(clippy::result_large_err)]
462impl SearchRelationsRequest {
463 #[allow(clippy::result_large_err)]
464 pub fn validate_for_browser(
465 &mut self,
466 datastore_id: crate::PublicUuid,
467 protocol_version: &ProtocolVersion,
468 ) -> Result<(), ProtocolError> {
469 let mut issues = Vec::new();
470 collect_entity_predicate_set_issues("body.predicates", &self.predicates, &mut issues);
471 collect_relation_predicate_issues(&mut self.predicates, &mut issues);
472 if let Err(message) = self.page.validate() {
473 issues.push(ValidationIssue::new(
474 "body.page.limit",
475 ValidationIssueCode::OutOfRange,
476 message,
477 ));
478 }
479 if let Some(raw_cursor) = self.page.cursor.as_deref() {
480 match serde_json::from_str::<BrowserRelationSearchCursor>(raw_cursor) {
481 Ok(cursor)
482 if cursor.binding
483 == self.browser_cursor_binding(datastore_id, protocol_version) => {}
484 Ok(_) => issues.push(ValidationIssue::new(
485 "body.page.cursor",
486 ValidationIssueCode::Conflict,
487 "browser model-relation search cursor does not match the datastore, search family, predicates, page limit, or protocol version",
488 )),
489 Err(_) => issues.push(ValidationIssue::new(
490 "body.page.cursor",
491 ValidationIssueCode::InvalidFormat,
492 "browser model-relation search cursor is invalid",
493 )),
494 }
495 }
496 if issues.is_empty() {
497 Ok(())
498 } else {
499 Err(ProtocolError::validation(
500 "browser model-relation search request is invalid",
501 issues,
502 ))
503 }
504 }
505
506 #[allow(clippy::result_large_err)]
507 pub fn browser_decoded_cursor(
508 &self,
509 datastore_id: crate::PublicUuid,
510 protocol_version: &ProtocolVersion,
511 ) -> Result<Option<RelationSearchCursorAnchor>, ProtocolError> {
512 let Some(raw_cursor) = self.page.cursor.as_deref() else {
513 return Ok(None);
514 };
515 let cursor: BrowserRelationSearchCursor =
516 serde_json::from_str(raw_cursor).map_err(|_| {
517 ProtocolError::validation(
518 "browser model-relation search request is invalid",
519 vec![ValidationIssue::new(
520 "body.page.cursor",
521 ValidationIssueCode::InvalidFormat,
522 "browser model-relation search cursor is invalid",
523 )],
524 )
525 })?;
526 if cursor.binding != self.browser_cursor_binding(datastore_id, protocol_version) {
527 return Err(ProtocolError::validation(
528 "browser model-relation search request is invalid",
529 vec![ValidationIssue::new(
530 "body.page.cursor",
531 ValidationIssueCode::Conflict,
532 "browser model-relation search cursor does not match the datastore, search family, predicates, page limit, or protocol version",
533 )],
534 ));
535 }
536 Ok(Some(cursor.after))
537 }
538
539 #[allow(clippy::result_large_err)]
540 pub fn encode_browser_cursor(
541 &self,
542 datastore_id: crate::PublicUuid,
543 protocol_version: &ProtocolVersion,
544 after: RelationSearchCursorAnchor,
545 ) -> Result<String, ProtocolError> {
546 serde_json::to_string(&BrowserRelationSearchCursor {
547 binding: self.browser_cursor_binding(datastore_id, protocol_version),
548 after,
549 })
550 .map_err(|error| {
551 ProtocolError::new(
552 crate::public_error::ProtocolErrorCode::Internal,
553 format!("failed to encode browser model-relation search cursor: {error}"),
554 )
555 })
556 }
557 pub fn validate(&mut self, protocol_version: &ProtocolVersion) -> Result<(), ProtocolError> {
558 let mut issues = Vec::new();
559 collect_entity_predicate_set_issues("body.predicates", &self.predicates, &mut issues);
560 collect_relation_predicate_issues(&mut self.predicates, &mut issues);
561 if let Err(message) = self.page.validate() {
562 issues.push(ValidationIssue::new(
563 "body.page.limit",
564 ValidationIssueCode::OutOfRange,
565 message,
566 ));
567 }
568 collect_relation_cursor_issues(self, protocol_version, &mut issues);
569
570 if issues.is_empty() {
571 Ok(())
572 } else {
573 Err(ProtocolError::validation(
574 "relation search request is invalid",
575 issues,
576 ))
577 }
578 }
579
580 pub fn decoded_cursor(
581 &self,
582 protocol_version: &ProtocolVersion,
583 ) -> Result<Option<RelationSearchCursorAnchor>, ProtocolError> {
584 match self.page.cursor.as_deref() {
585 None => Ok(None),
586 Some(raw_cursor) => {
587 let cursor: RelationSearchCursor =
588 serde_json::from_str(raw_cursor).map_err(|error| {
589 ProtocolError::validation(
590 "relation search request is invalid",
591 vec![ValidationIssue::new(
592 "body.page.cursor",
593 ValidationIssueCode::InvalidFormat,
594 format!("relation search cursor is invalid: {error}"),
595 )],
596 )
597 })?;
598 let expected = self.cursor_binding(protocol_version);
599 if cursor.binding != expected {
600 return Err(ProtocolError::validation(
601 "relation search request is invalid",
602 vec![ValidationIssue::new(
603 "body.page.cursor",
604 ValidationIssueCode::Conflict,
605 "relation search cursor does not match the request predicates, page limit, or protocol version",
606 )],
607 ));
608 }
609 Ok(Some(cursor.after))
610 }
611 }
612 }
613
614 pub fn encode_cursor(
615 &self,
616 protocol_version: &ProtocolVersion,
617 after: RelationSearchCursorAnchor,
618 ) -> Result<String, ProtocolError> {
619 serde_json::to_string(&RelationSearchCursor {
620 binding: self.cursor_binding(protocol_version),
621 after,
622 })
623 .map_err(|error| {
624 ProtocolError::new(
625 crate::public_error::ProtocolErrorCode::Internal,
626 format!("failed to encode relation search cursor: {error}"),
627 )
628 })
629 }
630
631 fn cursor_binding(
632 &self,
633 protocol_version: &ProtocolVersion,
634 ) -> SearchCursorBinding<RelationSearchCursorQuery> {
635 SearchCursorBinding {
636 query: RelationSearchCursorQuery {
637 predicates: self.predicates.clone(),
638 },
639 page_limit: self.page.limit,
640 protocol_version: protocol_version.to_string(),
641 }
642 }
643
644 fn browser_cursor_binding(
645 &self,
646 datastore_id: crate::PublicUuid,
647 protocol_version: &ProtocolVersion,
648 ) -> SearchCursorBinding<BrowserRelationSearchCursorQuery> {
649 SearchCursorBinding {
650 query: BrowserRelationSearchCursorQuery {
651 datastore_id,
652 family: "model_relations".to_string(),
653 predicates: self.predicates.clone(),
654 },
655 page_limit: self.page.limit,
656 protocol_version: protocol_version.to_string(),
657 }
658 }
659}
660
661#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
662pub struct ListEntitiesRequest {
663 #[serde(default, skip_serializing_if = "Option::is_none")]
664 pub session: Option<SessionSelector>,
665 pub domain: DomainSelector,
666}
667
668#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
669pub struct GetEntityRequest {
670 #[serde(default, skip_serializing_if = "Option::is_none")]
671 pub session: Option<SessionSelector>,
672 pub entity: EntitySelector,
673}
674
675#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
676pub struct AddEntityRequest {
677 #[serde(default, skip_serializing_if = "Option::is_none")]
678 pub session: Option<SessionSelector>,
679 pub domain: DomainSelector,
680 pub name: PublicName,
681 #[serde(default, skip_serializing_if = "Option::is_none")]
682 pub description: Option<String>,
683 #[serde(default, skip_serializing_if = "Option::is_none")]
684 pub agent_instructions: Option<String>,
685 #[serde(default, skip_serializing_if = "Option::is_none")]
686 pub ontology_namespace: Option<String>,
687 #[serde(default, skip_serializing_if = "Option::is_none")]
688 pub ontology_class: Option<String>,
689 pub intent: ModelMutationIntent,
690}
691
692#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
693pub struct EntityListResponse {
694 pub entities: Vec<EntitySummary>,
695 #[serde(default, skip_serializing_if = "Option::is_none")]
696 pub next_cursor: Option<String>,
697 #[serde(default, skip_serializing_if = "Option::is_none")]
698 pub warnings: Option<ModelWarnings>,
699}
700
701#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
702pub struct EntityDetailResponse {
703 pub entity: EntityDetail,
704 #[serde(default, skip_serializing_if = "Option::is_none")]
705 pub warnings: Option<ModelWarnings>,
706}
707
708#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
709pub struct EntityInstanceGetRequest {
710 #[serde(default, skip_serializing_if = "Option::is_none")]
711 pub session: Option<SessionSelector>,
712 pub instance_id: crate::refs::ObjectRef,
713}
714
715#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
716pub struct EntityInstanceListRequest {
717 #[serde(default, skip_serializing_if = "Option::is_none")]
718 pub session: Option<SessionSelector>,
719 pub entity: EntitySelector,
720}
721
722#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
723pub struct EntityInstanceAddRequest {
724 #[serde(default, skip_serializing_if = "Option::is_none")]
725 pub session: Option<SessionSelector>,
726 pub entity: EntitySelector,
727 #[serde(default, skip_serializing_if = "Option::is_none")]
728 pub transformation_id: Option<crate::refs::ObjectRef>,
729 #[serde(default, skip_serializing_if = "Option::is_none")]
730 pub label: Option<String>,
731 #[serde(default, skip_serializing_if = "Option::is_none")]
732 pub note: Option<String>,
733 pub intent: ModelMutationIntent,
734}
735
736pub type EntityInstanceListResponse = SemanticInstanceListResponse;
737
738pub type EntityInstanceDetailResponse = SemanticInstanceDetailResponse;
739
740#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
741pub struct EntityInstanceMapAddRequest {
742 #[serde(default, skip_serializing_if = "Option::is_none")]
743 pub session: Option<SessionSelector>,
744 pub study: SemanticInput<crate::study::StudySelector>,
745 pub instance_id: crate::refs::ObjectRef,
746 pub external_id: String,
747 #[serde(default, skip_serializing_if = "Option::is_none")]
748 pub transformation_id: Option<crate::refs::ObjectRef>,
749 pub intent: ModelMutationIntent,
750}
751
752#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
753pub struct EntityInstanceMapGetRequest {
754 #[serde(default, skip_serializing_if = "Option::is_none")]
755 pub session: Option<SessionSelector>,
756 pub study: SemanticInput<crate::study::StudySelector>,
757 pub entity: EntitySelector,
758 pub external_id: String,
759}
760
761#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
762pub struct EntityInstanceMapListRequest {
763 #[serde(default, skip_serializing_if = "Option::is_none")]
764 pub session: Option<SessionSelector>,
765 pub study: SemanticInput<crate::study::StudySelector>,
766 #[serde(default, skip_serializing_if = "Option::is_none")]
767 pub entity: Option<EntitySelector>,
768}
769
770pub type EntityInstanceMapResponse = SemanticMappingDetailResponse;
771
772#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
773pub struct EntityInstanceAssetLinkAddRequest {
774 #[serde(default, skip_serializing_if = "Option::is_none")]
775 pub session: Option<SessionSelector>,
776 pub study: SemanticInput<crate::study::StudySelector>,
777 pub instance_id: crate::refs::ObjectRef,
778 pub asset: SemanticInput<crate::asset::AssetSelector>,
779 #[serde(default, skip_serializing_if = "Option::is_none")]
780 pub version: Option<String>,
781 #[serde(default, skip_serializing_if = "Option::is_none")]
782 pub transformation_id: Option<crate::refs::ObjectRef>,
783 pub intent: ModelMutationIntent,
784}
785
786#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
787pub struct EntityInstanceAssetLinkListRequest {
788 #[serde(default, skip_serializing_if = "Option::is_none")]
789 pub session: Option<SessionSelector>,
790 #[serde(default, skip_serializing_if = "Option::is_none")]
791 pub instance_id: Option<crate::refs::ObjectRef>,
792 #[serde(default, skip_serializing_if = "Option::is_none")]
793 pub study: Option<SemanticInput<crate::study::StudySelector>>,
794 #[serde(default, skip_serializing_if = "Option::is_none")]
795 pub asset: Option<SemanticInput<crate::asset::AssetSelector>>,
796 #[serde(default, skip_serializing_if = "Option::is_none")]
797 pub version: Option<String>,
798}
799
800#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
801pub struct EntityInstanceDatasetsRequest {
802 #[serde(default, skip_serializing_if = "Option::is_none")]
803 pub session: Option<SessionSelector>,
804 pub instance_id: crate::refs::ObjectRef,
805}
806
807#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
808pub struct EntityInstanceDatasetLinkAddRequest {
809 #[serde(default, skip_serializing_if = "Option::is_none")]
810 pub session: Option<SessionSelector>,
811 pub study: SemanticInput<crate::study::StudySelector>,
812 pub instance_id: crate::refs::ObjectRef,
813 pub dataset: SemanticInput<crate::dataset::DatasetSelector>,
814 pub variable: SemanticInput<crate::dictionary::VariableSelector>,
815 #[serde(default, skip_serializing_if = "Option::is_none")]
816 pub version: Option<String>,
817 #[serde(default, skip_serializing_if = "Option::is_none")]
818 pub transformation_id: Option<crate::refs::ObjectRef>,
819 pub intent: ModelMutationIntent,
820}
821
822#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
823pub struct EntityInstanceDatasetLinkGetRequest {
824 #[serde(default, skip_serializing_if = "Option::is_none")]
825 pub session: Option<SessionSelector>,
826 pub study: SemanticInput<crate::study::StudySelector>,
827 pub instance_id: crate::refs::ObjectRef,
828 pub dataset: SemanticInput<crate::dataset::DatasetSelector>,
829 #[serde(default, skip_serializing_if = "Option::is_none")]
830 pub version: Option<String>,
831}
832
833#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
834pub struct EntityInstanceDatasetLinkListRequest {
835 #[serde(default, skip_serializing_if = "Option::is_none")]
836 pub session: Option<SessionSelector>,
837 pub study: SemanticInput<crate::study::StudySelector>,
838 pub dataset: SemanticInput<crate::dataset::DatasetSelector>,
839 #[serde(default, skip_serializing_if = "Option::is_none")]
840 pub version: Option<String>,
841}
842
843pub type ModelLinkResponse = SemanticMutationResponse;
844
845pub type EntityInstanceDatasetLinkSummary = SemanticLinkReadback;
846
847pub type EntityInstanceDatasetLinkReadbackResponse = SemanticLinkListResponse;
848
849#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
850pub struct ListRelationsRequest {
851 #[serde(default, skip_serializing_if = "Option::is_none")]
852 pub session: Option<SessionSelector>,
853 pub domain: DomainSelector,
854}
855
856#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
857pub struct GetRelationRequest {
858 #[serde(default, skip_serializing_if = "Option::is_none")]
859 pub session: Option<SessionSelector>,
860 pub relation: RelationSelector,
861}
862
863#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
864pub struct AddRelationRequest {
865 #[serde(default, skip_serializing_if = "Option::is_none")]
866 pub session: Option<SessionSelector>,
867 pub domain: DomainSelector,
868 pub name: PublicName,
869 pub subject: PublicName,
870 pub object: PublicName,
871 #[serde(default, skip_serializing_if = "Option::is_none")]
872 pub description: Option<String>,
873 #[serde(default, skip_serializing_if = "Option::is_none")]
874 pub agent_instructions: Option<String>,
875 #[serde(default, skip_serializing_if = "Option::is_none")]
876 pub ontology_namespace: Option<String>,
877 #[serde(default, skip_serializing_if = "Option::is_none")]
878 pub ontology_class: Option<String>,
879 pub intent: ModelMutationIntent,
880}
881
882#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
883pub struct RelationListResponse {
884 pub relations: Vec<RelationDefinitionSummary>,
885 #[serde(default, skip_serializing_if = "Option::is_none")]
886 pub next_cursor: Option<String>,
887 #[serde(default, skip_serializing_if = "Option::is_none")]
888 pub warnings: Option<ModelWarnings>,
889}
890
891#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
892pub struct RelationDetailResponse {
893 pub relation: RelationDefinitionDetail,
894 #[serde(default, skip_serializing_if = "Option::is_none")]
895 pub warnings: Option<ModelWarnings>,
896}
897
898#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
899pub struct RelationInstanceGetRequest {
900 #[serde(default, skip_serializing_if = "Option::is_none")]
901 pub session: Option<SessionSelector>,
902 pub relation_instance_id: crate::refs::ObjectRef,
903}
904
905#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
906pub struct RelationInstanceListRequest {
907 #[serde(default, skip_serializing_if = "Option::is_none")]
908 pub session: Option<SessionSelector>,
909 pub relation: RelationSelector,
910}
911
912#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
913pub struct RelationInstanceAddRequest {
914 #[serde(default, skip_serializing_if = "Option::is_none")]
915 pub session: Option<SessionSelector>,
916 pub relation: RelationSelector,
917 pub subject_instance_id: crate::refs::ObjectRef,
918 pub object_instance_id: crate::refs::ObjectRef,
919 #[serde(default, skip_serializing_if = "Option::is_none")]
920 pub transformation_id: Option<crate::refs::ObjectRef>,
921 #[serde(default, skip_serializing_if = "Option::is_none")]
922 pub valid_from: Option<String>,
923 #[serde(default, skip_serializing_if = "Option::is_none")]
924 pub valid_to: Option<String>,
925 #[serde(default, skip_serializing_if = "Option::is_none")]
926 pub note: Option<String>,
927 pub intent: ModelMutationIntent,
928}
929
930pub type RelationInstanceListResponse = SemanticInstanceListResponse;
931
932pub type RelationInstanceDetailResponse = SemanticInstanceDetailResponse;
933
934#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
935pub struct RelationInstanceMapAddRequest {
936 #[serde(default, skip_serializing_if = "Option::is_none")]
937 pub session: Option<SessionSelector>,
938 pub study: SemanticInput<crate::study::StudySelector>,
939 pub relation_instance_id: crate::refs::ObjectRef,
940 pub external_id: String,
941 #[serde(default, skip_serializing_if = "Option::is_none")]
942 pub transformation_id: Option<crate::refs::ObjectRef>,
943 pub intent: ModelMutationIntent,
944}
945
946#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
947pub struct RelationInstanceMapGetRequest {
948 #[serde(default, skip_serializing_if = "Option::is_none")]
949 pub session: Option<SessionSelector>,
950 pub study: SemanticInput<crate::study::StudySelector>,
951 pub relation: RelationSelector,
952 pub external_id: String,
953}
954
955#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
956pub struct RelationInstanceMapListRequest {
957 #[serde(default, skip_serializing_if = "Option::is_none")]
958 pub session: Option<SessionSelector>,
959 pub study: SemanticInput<crate::study::StudySelector>,
960 #[serde(default, skip_serializing_if = "Option::is_none")]
961 pub relation: Option<RelationSelector>,
962}
963
964pub type RelationInstanceMapResponse = SemanticMappingDetailResponse;
965
966pub type RelationInstanceMappingSummary = SemanticMappingReadback;
967
968pub type RelationInstanceMapListResponse = SemanticMappingListResponse;
969
970#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
971pub struct RelationInstanceAssetLinkAddRequest {
972 #[serde(default, skip_serializing_if = "Option::is_none")]
973 pub session: Option<SessionSelector>,
974 pub study: SemanticInput<crate::study::StudySelector>,
975 pub relation_instance_id: crate::refs::ObjectRef,
976 pub asset: SemanticInput<crate::asset::AssetSelector>,
977 #[serde(default, skip_serializing_if = "Option::is_none")]
978 pub version: Option<String>,
979 #[serde(default, skip_serializing_if = "Option::is_none")]
980 pub transformation_id: Option<crate::refs::ObjectRef>,
981 pub intent: ModelMutationIntent,
982}
983
984#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
985pub struct RelationInstanceAssetLinkListRequest {
986 #[serde(default, skip_serializing_if = "Option::is_none")]
987 pub session: Option<SessionSelector>,
988 #[serde(default, skip_serializing_if = "Option::is_none")]
989 pub relation_instance_id: Option<crate::refs::ObjectRef>,
990 #[serde(default, skip_serializing_if = "Option::is_none")]
991 pub study: Option<SemanticInput<crate::study::StudySelector>>,
992 #[serde(default, skip_serializing_if = "Option::is_none")]
993 pub asset: Option<SemanticInput<crate::asset::AssetSelector>>,
994 #[serde(default, skip_serializing_if = "Option::is_none")]
995 pub version: Option<String>,
996}
997
998pub type RelationInstanceAssetLinkSummary = SemanticLinkReadback;
999
1000pub type RelationInstanceAssetLinkListResponse = SemanticLinkListResponse;
1001
1002#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1003pub struct RelationInstanceDatasetLinkAddRequest {
1004 #[serde(default, skip_serializing_if = "Option::is_none")]
1005 pub session: Option<SessionSelector>,
1006 pub study: SemanticInput<crate::study::StudySelector>,
1007 pub relation_instance_id: crate::refs::ObjectRef,
1008 pub dataset: SemanticInput<crate::dataset::DatasetSelector>,
1009 pub subject_variable: SemanticInput<crate::dictionary::VariableSelector>,
1010 pub object_variable: SemanticInput<crate::dictionary::VariableSelector>,
1011 #[serde(default, skip_serializing_if = "Option::is_none")]
1012 pub relation_variable: Option<SemanticInput<crate::dictionary::VariableSelector>>,
1013 #[serde(default, skip_serializing_if = "Option::is_none")]
1014 pub version: Option<String>,
1015 #[serde(default, skip_serializing_if = "Option::is_none")]
1016 pub transformation_id: Option<crate::refs::ObjectRef>,
1017 pub intent: ModelMutationIntent,
1018}
1019
1020#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1021pub struct RelationInstanceDatasetLinkGetRequest {
1022 #[serde(default, skip_serializing_if = "Option::is_none")]
1023 pub session: Option<SessionSelector>,
1024 pub study: SemanticInput<crate::study::StudySelector>,
1025 pub relation_instance_id: crate::refs::ObjectRef,
1026 pub dataset: SemanticInput<crate::dataset::DatasetSelector>,
1027 #[serde(default, skip_serializing_if = "Option::is_none")]
1028 pub version: Option<String>,
1029}
1030
1031#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1032pub struct RelationInstanceDatasetLinkListRequest {
1033 #[serde(default, skip_serializing_if = "Option::is_none")]
1034 pub session: Option<SessionSelector>,
1035 pub study: SemanticInput<crate::study::StudySelector>,
1036 pub dataset: SemanticInput<crate::dataset::DatasetSelector>,
1037 #[serde(default, skip_serializing_if = "Option::is_none")]
1038 pub version: Option<String>,
1039}
1040
1041pub type RelationInstanceDatasetLinkSummary = SemanticLinkReadback;
1042
1043pub type RelationInstanceDatasetLinkReadbackResponse = SemanticLinkListResponse;
1044
1045#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1048#[serde(untagged)]
1049pub enum SemanticInput<T> {
1050 Name(PublicName),
1051 Selector(T),
1052 Reference(crate::refs::ObjectRef),
1053}
1054impl<T> From<PublicName> for SemanticInput<T> {
1055 fn from(name: PublicName) -> Self {
1056 Self::Name(name)
1057 }
1058}
1059impl<T> SemanticInput<T> {
1060 pub fn into_legacy_name(self) -> Result<PublicName, &'static str> {
1061 match self {
1062 Self::Name(name) => Ok(name),
1063 _ => Err("Canonical semantic selectors require a Managed Session"),
1064 }
1065 }
1066}
1067
1068#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1069pub struct EntityInstanceEnsureFromDatasetRequest {
1070 #[serde(default, skip_serializing_if = "Option::is_none")]
1071 pub session: Option<SessionSelector>,
1072 pub study: SemanticInput<crate::study::StudySelector>,
1073 pub entity: EntitySelector,
1074 pub dataset: SemanticInput<crate::dataset::DatasetSelector>,
1075 #[serde(default, skip_serializing_if = "Option::is_none")]
1076 pub version: Option<String>,
1077 pub external_id_variable: SemanticInput<crate::dictionary::VariableSelector>,
1078 #[serde(default, skip_serializing_if = "Option::is_none")]
1079 pub label_template: Option<String>,
1080 pub intent: SemanticWorkflowIntent,
1081}
1082
1083#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1084pub struct RelationInstanceEnsureFromDatasetRequest {
1085 #[serde(default, skip_serializing_if = "Option::is_none")]
1086 pub session: Option<SessionSelector>,
1087 pub study: SemanticInput<crate::study::StudySelector>,
1088 pub relation: RelationSelector,
1089 pub dataset: SemanticInput<crate::dataset::DatasetSelector>,
1090 #[serde(default, skip_serializing_if = "Option::is_none")]
1091 pub version: Option<String>,
1092 pub relation_external_id_variable: SemanticInput<crate::dictionary::VariableSelector>,
1093 pub subject_external_id_variable: SemanticInput<crate::dictionary::VariableSelector>,
1094 pub object_external_id_variable: SemanticInput<crate::dictionary::VariableSelector>,
1095 #[serde(default, skip_serializing_if = "Option::is_none")]
1096 pub valid_from_variable: Option<SemanticInput<crate::dictionary::VariableSelector>>,
1097 #[serde(default, skip_serializing_if = "Option::is_none")]
1098 pub valid_to_variable: Option<SemanticInput<crate::dictionary::VariableSelector>>,
1099 pub intent: SemanticWorkflowIntent,
1100}
1101
1102#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1103pub struct SemanticWorkflowIntent {
1104 #[serde(default)]
1105 pub dry_run: bool,
1106 #[serde(default)]
1107 pub create_transformation: bool,
1108}
1109
1110#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1111pub struct EntityInstanceEnsureFromDatasetResponse {
1112 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1113 pub instances: Vec<SemanticInstanceReadback>,
1114 pub summary: EntityInstanceEnsureFromDatasetSummary,
1115 pub counts: EntityInstanceEnsureFromDatasetCounts,
1116 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1117 pub conflicts: Vec<SemanticWorkflowConflict>,
1118 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1119 pub rejected_rows: Vec<SemanticWorkflowRejectedRow>,
1120 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1121 pub warnings: Vec<String>,
1122}
1123
1124#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1125pub struct RelationInstanceEnsureFromDatasetResponse {
1126 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1127 pub instances: Vec<SemanticInstanceReadback>,
1128 pub summary: RelationInstanceEnsureFromDatasetSummary,
1129 pub counts: RelationInstanceEnsureFromDatasetCounts,
1130 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1131 pub conflicts: Vec<SemanticWorkflowConflict>,
1132 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1133 pub missing_endpoints: Vec<RelationInstanceMissingEndpointSummary>,
1134 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1135 pub rejected_rows: Vec<SemanticWorkflowRejectedRow>,
1136 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1137 pub warnings: Vec<String>,
1138}
1139
1140#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1141pub struct EntityInstanceEnsureFromDatasetSummary {
1142 #[serde(default, skip_serializing_if = "Option::is_none")]
1143 pub references: Option<SemanticBatchReferences>,
1144 pub schema_version: String,
1145 pub operation: String,
1146 pub dry_run: bool,
1147 pub study: String,
1148 pub entity: EntitySelectorSummary,
1149 pub dataset: String,
1150 #[serde(default, skip_serializing_if = "Option::is_none")]
1151 pub requested_version: Option<String>,
1152 pub resolved_version: String,
1153 pub external_id_variable: String,
1154 #[serde(default, skip_serializing_if = "Option::is_none")]
1155 pub label_template: Option<String>,
1156 #[serde(default, skip_serializing_if = "Option::is_none")]
1157 pub transformation: Option<SemanticWorkflowTransformationSummary>,
1158}
1159
1160#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1161pub struct RelationInstanceEnsureFromDatasetSummary {
1162 #[serde(default, skip_serializing_if = "Option::is_none")]
1163 pub references: Option<SemanticBatchReferences>,
1164 pub schema_version: String,
1165 pub operation: String,
1166 pub dry_run: bool,
1167 pub study: String,
1168 pub relation: RelationSelectorSummary,
1169 pub dataset: String,
1170 #[serde(default, skip_serializing_if = "Option::is_none")]
1171 pub requested_version: Option<String>,
1172 pub resolved_version: String,
1173 pub relation_external_id_variable: String,
1174 pub subject_external_id_variable: String,
1175 pub object_external_id_variable: String,
1176 #[serde(default, skip_serializing_if = "Option::is_none")]
1177 pub valid_from_variable: Option<String>,
1178 #[serde(default, skip_serializing_if = "Option::is_none")]
1179 pub valid_to_variable: Option<String>,
1180 #[serde(default, skip_serializing_if = "Option::is_none")]
1181 pub transformation: Option<SemanticWorkflowTransformationSummary>,
1182}
1183
1184#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1185pub struct EntitySelectorSummary {
1186 pub domain: String,
1187 pub name: String,
1188}
1189
1190#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1191pub struct RelationSelectorSummary {
1192 pub domain: String,
1193 pub name: String,
1194}
1195
1196#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1197pub struct SemanticWorkflowTransformationSummary {
1198 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1199 pub inputs: Vec<crate::refs::VersionRef>,
1200 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1201 pub outputs: Vec<crate::refs::VersionRef>,
1202 pub transformation_id: i64,
1203 pub transformation: crate::refs::TransformationRef,
1204 pub transformation_type: String,
1205 #[serde(default, skip_serializing_if = "Option::is_none")]
1206 pub description: Option<String>,
1207 pub input_count: usize,
1208 pub output_count: usize,
1209}
1210
1211#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1212pub struct EntityInstanceEnsureFromDatasetCounts {
1213 pub created_instances: usize,
1214 pub reused_instances: usize,
1215 pub created_study_mappings: usize,
1216 pub reused_study_mappings: usize,
1217 pub created_dataset_links: usize,
1218 pub reused_dataset_links: usize,
1219 pub rejected_rows: usize,
1220 pub conflicts: usize,
1221}
1222
1223#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1224pub struct RelationInstanceEnsureFromDatasetCounts {
1225 pub created_instances: usize,
1226 pub reused_instances: usize,
1227 pub created_study_mappings: usize,
1228 pub reused_study_mappings: usize,
1229 pub created_dataset_links: usize,
1230 pub reused_dataset_links: usize,
1231 pub missing_endpoints: usize,
1232 pub rejected_rows: usize,
1233 pub conflicts: usize,
1234}
1235
1236#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1237pub struct SemanticWorkflowConflict {
1238 pub external_id: String,
1239 pub message: String,
1240}
1241
1242#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1243pub struct RelationInstanceMissingEndpointSummary {
1244 pub relation_external_id: String,
1245 pub endpoint_role: String,
1246 pub endpoint_external_id: String,
1247 pub entity: EntityRef,
1248}
1249
1250#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1251pub struct SemanticWorkflowRejectedRow {
1252 pub row_number: usize,
1253 pub reason: String,
1254}
1255
1256#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1257#[serde(tag = "kind", rename_all = "snake_case")]
1258pub enum EntityPredicate {
1259 Text(TextPredicate<EntityTextField>),
1260 Domain { domain: DomainSelector },
1261 Tag(TagPredicate),
1262}
1263
1264#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1265#[serde(tag = "kind", rename_all = "snake_case")]
1266pub enum RelationPredicate {
1267 Text(TextPredicate<RelationTextField>),
1268 Domain { domain: DomainSelector },
1269 SourceEntity { entity: EntitySelector },
1270 TargetEntity { entity: EntitySelector },
1271 Tag(TagPredicate),
1272}
1273
1274#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1275#[serde(rename_all = "snake_case")]
1276pub enum EntityTextField {
1277 Name,
1278 Description,
1279 OntologyClass,
1280}
1281
1282fn collect_entity_predicate_set_issues<P>(
1283 path: &str,
1284 predicates: &PredicateSet<P>,
1285 issues: &mut Vec<ValidationIssue>,
1286) {
1287 if let Err(message) = predicates.validate() {
1288 issues.push(ValidationIssue::new(
1289 path,
1290 ValidationIssueCode::InvalidValue,
1291 message,
1292 ));
1293 }
1294}
1295
1296fn collect_entity_predicate_issues(
1297 predicates: &mut PredicateSet<EntityPredicate>,
1298 issues: &mut Vec<ValidationIssue>,
1299) {
1300 for (index, predicate) in predicates.predicates_mut().iter_mut().enumerate() {
1301 if let EntityPredicate::Text(text) = predicate
1302 && let Err(message) = text.validate()
1303 {
1304 issues.push(ValidationIssue::new(
1305 format!("body.predicates.predicates[{index}].value"),
1306 ValidationIssueCode::InvalidValue,
1307 message,
1308 ));
1309 }
1310 }
1311}
1312
1313fn collect_entity_cursor_issues(
1314 request: &SearchEntitiesRequest,
1315 protocol_version: &ProtocolVersion,
1316 issues: &mut Vec<ValidationIssue>,
1317) {
1318 if request.page.cursor.is_some()
1319 && let Err(error) = request.decoded_cursor(protocol_version)
1320 {
1321 issues.extend(error.issues.iter().cloned());
1322 }
1323}
1324
1325fn collect_relation_predicate_issues(
1326 predicates: &mut PredicateSet<RelationPredicate>,
1327 issues: &mut Vec<ValidationIssue>,
1328) {
1329 for (index, predicate) in predicates.predicates_mut().iter_mut().enumerate() {
1330 if let RelationPredicate::Text(text) = predicate
1331 && let Err(message) = text.validate()
1332 {
1333 issues.push(ValidationIssue::new(
1334 format!("body.predicates.predicates[{index}].value"),
1335 ValidationIssueCode::InvalidValue,
1336 message,
1337 ));
1338 }
1339 }
1340}
1341
1342fn collect_relation_cursor_issues(
1343 request: &SearchRelationsRequest,
1344 protocol_version: &ProtocolVersion,
1345 issues: &mut Vec<ValidationIssue>,
1346) {
1347 if request.page.cursor.is_some()
1348 && let Err(error) = request.decoded_cursor(protocol_version)
1349 {
1350 issues.extend(error.issues.iter().cloned());
1351 }
1352}
1353
1354#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1355#[serde(rename_all = "snake_case")]
1356pub enum RelationTextField {
1357 Name,
1358 Description,
1359 SourceEntityName,
1360 TargetEntityName,
1361 OntologyClass,
1362}
1363
1364#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1366pub struct SemanticBatchReferences {
1367 pub study: crate::refs::StudyRef,
1368 pub definition: crate::refs::ObjectRef,
1369 pub dataset: crate::refs::DatasetRef,
1370 pub version: crate::refs::VersionRef,
1371 pub variables: Vec<crate::refs::VariableRef>,
1372}
1373#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1375pub struct SemanticInstanceReadback {
1376 pub instance: crate::refs::ObjectRef,
1377 pub definition: crate::refs::ObjectRef,
1378 pub transformation: crate::refs::TransformationRef,
1379 #[serde(default, skip_serializing_if = "Option::is_none")]
1380 pub label: Option<String>,
1381 #[serde(default, skip_serializing_if = "Option::is_none")]
1382 pub note: Option<String>,
1383 #[serde(default, skip_serializing_if = "Option::is_none")]
1384 pub subject: Option<crate::refs::EntityInstanceRef>,
1385 #[serde(default, skip_serializing_if = "Option::is_none")]
1386 pub object: Option<crate::refs::EntityInstanceRef>,
1387 #[serde(default, skip_serializing_if = "Option::is_none")]
1388 pub valid_from: Option<chrono::NaiveDate>,
1389 #[serde(default, skip_serializing_if = "Option::is_none")]
1390 pub valid_to: Option<chrono::NaiveDate>,
1391}
1392
1393#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1395pub struct SemanticInstanceDetailResponse {
1396 pub instance: SemanticInstanceReadback,
1397}
1398#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1399pub struct SemanticInstanceListResponse {
1400 pub instances: Vec<SemanticInstanceReadback>,
1401}
1402#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1403pub struct SemanticMappingReadback {
1404 pub study: crate::refs::StudyRef,
1405 pub definition: crate::refs::ObjectRef,
1406 pub instance: SemanticInstanceReadback,
1407 pub external_id: String,
1408 pub transformation: crate::refs::TransformationRef,
1409}
1410#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1411pub struct SemanticMappingDetailResponse {
1412 pub instance: Option<SemanticInstanceReadback>,
1414 pub mapping: Option<SemanticMappingReadback>,
1415}
1416#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1417pub struct SemanticMappingListResponse {
1418 pub study: crate::refs::StudyRef,
1419 pub mappings: Vec<SemanticMappingReadback>,
1420}
1421#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1422pub struct SemanticLinkReadback {
1423 pub version: crate::refs::VersionRef,
1424 pub asset: crate::refs::AssetRef,
1425 pub study: crate::refs::StudyRef,
1426 pub instance: SemanticInstanceReadback,
1427 pub transformation: crate::refs::TransformationRef,
1428 #[serde(default, skip_serializing_if = "Option::is_none")]
1429 pub mapping: Option<SemanticMappingReadback>,
1430 #[serde(default, skip_serializing_if = "Option::is_none")]
1431 pub variable: Option<crate::refs::VariableRef>,
1432 #[serde(default, skip_serializing_if = "Option::is_none")]
1433 pub subject_variable: Option<crate::refs::VariableRef>,
1434 #[serde(default, skip_serializing_if = "Option::is_none")]
1435 pub object_variable: Option<crate::refs::VariableRef>,
1436 #[serde(default, skip_serializing_if = "Option::is_none")]
1437 pub relation_variable: Option<crate::refs::VariableRef>,
1438}
1439#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1440pub struct SemanticLinkListResponse {
1441 pub links: Vec<SemanticLinkReadback>,
1442}
1443#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1446pub struct SemanticMutationResponse {
1447 #[serde(flatten)]
1448 pub target: SemanticMutationTarget,
1449 pub content_withheld: bool,
1450 pub transformation: SemanticMutationAttribution,
1451}
1452#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1453pub struct SemanticMutationAttribution {
1454 pub transformation: crate::refs::TransformationRef,
1455 pub inputs: Vec<crate::refs::VersionRef>,
1456 pub outputs: Vec<crate::refs::VersionRef>,
1457}
1458#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1459#[serde(untagged)]
1460pub enum SemanticMutationTarget {
1461 Instance { instance: SemanticInstanceIdentity },
1462 Mapping { mapping: SemanticMappingIdentity },
1463 Link { link: SemanticLinkIdentity },
1464}
1465#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1466pub struct SemanticInstanceIdentity {
1467 pub instance: crate::refs::ObjectRef,
1468 pub definition: crate::refs::ObjectRef,
1469}
1470#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1471pub struct SemanticMappingIdentity {
1472 pub study: crate::refs::StudyRef,
1473 pub instance: crate::refs::ObjectRef,
1474 pub transformation: crate::refs::TransformationRef,
1475}
1476#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1477pub struct SemanticLinkIdentity {
1478 pub version: crate::refs::VersionRef,
1479 pub instance: crate::refs::ObjectRef,
1480 pub transformation: crate::refs::TransformationRef,
1481 #[serde(default, skip_serializing_if = "Option::is_none")]
1482 pub variable: Option<crate::refs::VariableRef>,
1483 #[serde(default, skip_serializing_if = "Option::is_none")]
1484 pub subject_variable: Option<crate::refs::VariableRef>,
1485 #[serde(default, skip_serializing_if = "Option::is_none")]
1486 pub object_variable: Option<crate::refs::VariableRef>,
1487 #[serde(default, skip_serializing_if = "Option::is_none")]
1488 pub relation_variable: Option<crate::refs::VariableRef>,
1489}