//! Modifying the state of Foo objects on the server is done via the
//! "Foo/set" method. This encompasses creating, updating, and
//! destroying Foo records. This allows the server to sort out ordering
//! and dependencies that may exist if doing multiple operations at once
//! (for example, to ensure there is always a minimum number of a certain
//! record type).
use std::{borrow::Cow, collections::HashMap};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use serde_with::{serde_as, BorrowCow};
use crate::{common::Id, endpoints::object::ObjectState};
#[serde_as]
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct SetParams<'a, T> {
/// The id of the account to use.
account_id: Id<'a>,
/// This is a state string as returned by the "Foo/get" method
/// (representing the state of all objects of this type in the
/// account). If supplied, the string must match the current state;
/// otherwise, the method will be aborted and a "stateMismatch" error
/// returned. If null, any changes will be applied to the current
/// state.
#[serde(borrow)]
if_in_state: Option<ObjectState<'a>>,
/// A map of a *creation id* (a temporary id set by the client) to Foo
/// objects, or null if no objects are to be created.
///
/// The Foo object type definition may define default values for
/// properties. Any such property may be omitted by the client.
///
/// The client MUST omit any properties that may only be set by the
/// server (for example, the "id" property on most object types).
#[serde(default)]
create: HashMap<Id<'a>, T>,
/// A map of an id to a Patch object to apply to the current Foo
/// object with that id, or null if no objects are to be updated.
#[serde(default)]
update: HashMap<Id<'a>, PatchObject<'a>>,
/// A list of ids for Foo objects to permanently delete, or null if no
/// objects are to be destroyed.
#[serde(default)]
destroy: Vec<Id<'a>>,
}
/// A *PatchObject* is of type "String[*]" and represents an unordered
/// set of patches. The keys are a path in JSON Pointer format
/// [RFC6901], with an implicit leading "/" (i.e., prefix each key
/// with "/" before applying the JSON Pointer evaluation algorithm).
#[serde_as]
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct PatchObject<'a>(#[serde_as(as = "HashMap<BorrowCow, _>")] HashMap<Cow<'a, str>, Value>);
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct SetResult<'a, T> {
/// The id of the account used for the call.
#[serde(borrow)]
account_id: Id<'a>,
/// The state string that would have been returned by "Foo/get" before
/// making the requested changes, or null if the server doesn't know
/// what the previous state string was.
#[serde(borrow)]
old_state: Option<ObjectState<'a>>,
/// The state string that will now be returned by "Foo/get".
#[serde(borrow)]
new_state: ObjectState<'a>,
/// A map of the creation id to an object containing any properties of
/// the created Foo object that were not sent by the client. This
/// includes all server-set properties (such as the "id" in most
/// object types) and any properties that were omitted by the client
/// and thus set to a default by the server.
///
/// This argument is null if no Foo objects were successfully created.
#[serde(default, borrow)]
created: HashMap<Id<'a>, T>,
/// The keys in this map are the ids of all Foos that were
/// successfully updated.
///
/// The value for each id is a Foo object containing any property that
/// changed in a way *not* explicitly requested by the PatchObject
/// sent to the server, or null if none. This lets the client know of
/// any changes to server-set or computed properties.
///
/// This argument is null if no Foo objects were successfully updated.
#[serde(default, borrow)]
updated: HashMap<Id<'a>, Option<T>>,
/// A list of Foo ids for records that were successfully destroyed, or
/// null if none.
#[serde(default, borrow)]
destroyed: Vec<Id<'a>>,
/// A map of the creation id to a SetError object for each record that
/// failed to be created, or null if all successful.
#[serde(default, borrow)]
not_created: HashMap<Id<'a>, SetError<'a>>,
/// A map of the Foo id to a SetError object for each record that
/// failed to be updated, or null if all successful.
#[serde(default, borrow)]
not_updated: HashMap<Id<'a>, SetError<'a>>,
/// A map of the Foo id to a SetError object for each record that
/// failed to be destroyed, or null if all successful.
#[serde(default, borrow)]
not_destroyed: HashMap<Id<'a>, SetError<'a>>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct SetError<'a> {
/// The type of error.
#[serde(rename = "type")]
type_: SetErrorKind,
/// A description of the error to help with debugging that includes an
/// explanation of what the problem was. This is a non-localised
/// string and is not intended to be shown directly to end users.
#[serde(borrow)]
description: Option<Cow<'a, str>>,
/// The SetError object SHOULD also have a property called "properties" of
/// type "String[]" that lists *all* the properties that were invalid. For
/// type of `invalidProperties`.
#[serde(borrow)]
properties: Vec<Cow<'a, str>>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub enum SetErrorKind {
/// (create; update; destroy). The create/update/destroy would violate
/// an ACL or other permissions policy.
Forbidden,
/// (create; update). The create would exceed a server-defined limit
/// on the number or total size of objects of this type.
OverQuota,
/// (create; update). The create/update would result in an object that
/// exceeds a server-defined limit for the maximum size of a single object
/// of this type.
TooLarge,
/// (create). Too many objects of this type have been created recently,
/// and a server-defined rate limit has been reached. It may work if tried
/// again later.
RateLimit,
/// (update; destroy). The id given to update/destroy cannot be found.
NotFound,
/// (update). The PatchObject given to update the record was not a valid
/// patch (see the patch description).
InvalidPatch,
/// (update). The client requested that an object be both updated and
/// destroyed in the same /set request, and the server has decided to
/// therefore ignore the update.
WillDestroy,
/// (create; update). The record given is invalid in some way. For
/// example:
///
/// - It contains properties that are invalid according to the type specification of this
/// record type.
/// - It contains a property that may only be set by the server (e.g., "id") and is different
/// to the current value. Note, to allow clients to pass whole objects back, it is not an
/// error to include a server-set property in an update as long as the value is identical to
/// the current value on the server.
/// - There is a reference to another record (foreign key), and the given id does not
/// correspond to a valid record.
InvalidProperties,
/// (create; destroy). This is a singleton type, so you cannot create
/// another one or destroy the existing one.
Singleton,
}