coil_ops/bulk/
planning.rs1use crate::error::OpsModelError;
2use crate::identifiers::BulkOperationId;
3use crate::validation::require_non_empty;
4use coil_auth::Capability;
5use coil_jobs::{IdempotencyKey, JobInstant, JobSpec, PlannedJob};
6
7use super::BulkOperationDefinition;
8
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct BulkOperationRequest {
11 pub execution_id: crate::BulkExecutionId,
12 pub definition_id: BulkOperationId,
13 pub requested_by: String,
14 pub requested_at: JobInstant,
15 pub target_count: usize,
16 pub scheduled_for: Option<JobInstant>,
17 pub idempotency_key: Option<IdempotencyKey>,
18 pub operator_capabilities: Vec<Capability>,
19 pub dry_run: bool,
20}
21
22impl BulkOperationRequest {
23 pub fn new(
24 execution_id: crate::BulkExecutionId,
25 definition_id: BulkOperationId,
26 requested_by: impl Into<String>,
27 requested_at: JobInstant,
28 target_count: usize,
29 ) -> Result<Self, OpsModelError> {
30 Ok(Self {
31 execution_id,
32 definition_id,
33 requested_by: require_non_empty("bulk_requested_by", requested_by.into())?,
34 requested_at,
35 target_count,
36 scheduled_for: None,
37 idempotency_key: None,
38 operator_capabilities: Vec::new(),
39 dry_run: false,
40 })
41 }
42
43 pub fn scheduled_for(mut self, instant: JobInstant) -> Self {
44 self.scheduled_for = Some(instant);
45 self
46 }
47
48 pub fn with_idempotency_key(mut self, key: IdempotencyKey) -> Self {
49 self.idempotency_key = Some(key);
50 self
51 }
52
53 pub fn with_capability(mut self, capability: Capability) -> Self {
54 self.operator_capabilities.push(capability);
55 self
56 }
57
58 pub fn dry_run(mut self, dry_run: bool) -> Self {
59 self.dry_run = dry_run;
60 self
61 }
62}
63
64#[derive(Debug, Clone, PartialEq, Eq)]
65pub struct BulkOperationPlan {
66 pub definition: BulkOperationDefinition,
67 pub job: JobSpec,
68 pub planned_job: PlannedJob,
69 pub dry_run: bool,
70 pub target_count: usize,
71 pub audit_message: String,
72}