blob: 8741cf6cc65359fbf1628ec62f2693fdc771cfaf [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
use crate::{
schedule::Schedule,
task::{Create, Effect, Task},
};
use maka_agent_facts::configuration::Patch;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize)]
#[serde(
tag = "kind",
rename_all = "snake_case",
rename_all_fields = "camelCase",
deny_unknown_fields
)]
pub enum Query {
List {
cursor: Option<String>,
expected_revision: Option<u64>,
},
Get {
task_id: String,
},
}
impl Query {
pub fn validate(&self) -> Result<(), crate::Error> {
match self {
Self::Get { task_id } => crate::task::text(task_id),
Self::List {
cursor,
expected_revision,
} => {
if cursor.is_some() != expected_revision.is_some()
|| cursor.as_ref().is_some_and(|cursor| {
cursor.is_empty() || !cursor.bytes().all(|byte| byte.is_ascii_digit())
})
|| expected_revision.is_some_and(|revision| revision > (1 << 53) - 1)
{
return Err(crate::invalid(
"continuation requires a numeric cursor and revision",
));
}
Ok(())
}
}
}
}
#[derive(Clone, Debug, Deserialize)]
#[serde(
tag = "kind",
rename_all = "snake_case",
rename_all_fields = "camelCase",
deny_unknown_fields
)]
pub enum Mutation {
Create {
input: Create,
},
/// A caller-owned identity for creation that can be reconciled after losing a reply.
CreateOnce {
operation_id: uuid::Uuid,
input: Create,
},
Update {
task_id: String,
patch: Update,
},
Pause {
task_id: String,
},
Resume {
task_id: String,
},
ClearHistory {
task_id: String,
},
TriggerNow {
task_id: String,
},
Delete {
task_id: String,
},
Snooze {
task_id: String,
delay_ms: i64,
},
}
impl Mutation {
pub fn task_id(&self) -> Option<&str> {
match self {
Self::Create { .. } | Self::CreateOnce { .. } => None,
Self::Update { task_id, .. }
| Self::Pause { task_id }
| Self::Resume { task_id }
| Self::ClearHistory { task_id }
| Self::TriggerNow { task_id }
| Self::Delete { task_id }
| Self::Snooze { task_id, .. } => Some(task_id),
}
}
}
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[serde(bound(deserialize = "E: Deserialize<'de>"))]
pub struct Update<E = Effect> {
#[serde(default, deserialize_with = "present")]
pub title: Option<String>,
#[serde(default, deserialize_with = "present")]
pub intent_body: Option<String>,
#[serde(default, deserialize_with = "present")]
pub schedule: Option<Schedule>,
#[serde(default, deserialize_with = "present")]
pub effect: Option<E>,
#[serde(default)]
pub max_fires: Patch<u32>,
#[serde(default)]
pub expires_at: Patch<i64>,
}
impl<E> Default for Update<E> {
fn default() -> Self {
Self {
title: None,
intent_body: None,
schedule: None,
effect: None,
max_fires: Patch::Keep,
expires_at: Patch::Keep,
}
}
}
#[derive(Serialize, Deserialize)]
#[serde(
tag = "kind",
rename_all = "snake_case",
rename_all_fields = "camelCase"
)]
pub enum QueryResult {
Page {
revision: u64,
tasks: Vec<Task>,
next_cursor: Option<String>,
},
RevisionChanged {
expected: u64,
actual: u64,
},
Task {
revision: Option<u64>,
timezone: Option<String>,
task: Option<Box<Task>>,
},
}
#[derive(Serialize, Deserialize)]
#[serde(
tag = "kind",
rename_all = "snake_case",
rename_all_fields = "camelCase"
)]
pub enum MutationResult {
Task {
task: Box<Task>,
},
Created {
operation_id: uuid::Uuid,
task_id: String,
},
Deleted {
task_id: String,
},
}
fn present<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
where
D: serde::Deserializer<'de>,
T: Deserialize<'de>,
{
T::deserialize(deserializer).map(Some)
}