ticksupply 0.1.0

Official Rust client for the Ticksupply market data API
Documentation
//! export_schemas — List, inspect, and delete saved schemas used for
//! customized export output.
//!
//! This resource covers only the read/delete slice of the export-schemas
//! API. Saving a reusable schema (the draft → publish flow, atomic updates,
//! and typed column / unfold / derive maps the Python client exposes) is
//! not yet in the Rust SDK and is planned for a future release.
//!
//! To use custom columns **today** without a saved schema, pass a schema
//! object inline on each export via
//! [`CreateExportRequest::inline_schema`](crate::resources::exports::CreateExportRequest::inline_schema).
//! If you need to persist and reuse a schema now, the Python client or a
//! direct HTTP call against `/v1/export-schemas` is the stopgap.

use serde::Deserialize;

use crate::client::Client;
use crate::error::Result;
use crate::http::{send, send_empty, RequestOpts};
use crate::timestamp::Timestamp;

/// Slim schema metadata, returned by [`ExportSchemasResource::list`].
///
/// This is a flattened mix of the stored schema (id, name, stream_category,
/// is_built_in, created_at) plus the latest published version number and a
/// draft-present flag. Column bodies are not included in list responses.
#[derive(Debug, Clone, Deserialize)]
pub struct ExportSchemaListItem {
    /// Schema ID (`sch_…`).
    pub id: String,
    /// Human-friendly name.
    pub name: String,
    /// Stream category (e.g. `"trades"`, `"depth"`).
    pub stream_category: String,
    /// `true` for built-in schemas (e.g. `"raw"`, `"normalized"`).
    pub is_built_in: bool,
    /// Creation timestamp (RFC 3339 / ISO 8601).
    pub created_at: Timestamp,
    /// Latest published version number (`0` if no version has been
    /// published yet).
    pub version: i32,
    /// `true` if a draft is currently in progress for this schema.
    pub has_draft: bool,
}

/// Detailed schema, returned by [`ExportSchemasResource::get`]. The
/// `columns`, `unfold`, and `derive` fields are exposed as raw
/// [`serde_json::Value`] to avoid committing to a schema DSL the Rust
/// client does not yet fully mirror.
#[derive(Debug, Clone, Deserialize)]
pub struct ExportSchemaWithVersion {
    /// Schema ID (`sch_…`).
    pub id: String,
    /// Human-friendly name.
    pub name: String,
    /// Stream category.
    pub stream_category: String,
    /// `true` for built-in schemas.
    pub is_built_in: bool,
    /// Creation timestamp (RFC 3339 / ISO 8601).
    pub created_at: Timestamp,
    /// Latest published version number.
    pub version: i32,
    /// `true` if a draft is currently in progress.
    pub has_draft: bool,
    /// Column definitions for this version.
    pub columns: serde_json::Value,
    /// Optional unfold map.
    #[serde(default)]
    pub unfold: Option<serde_json::Value>,
    /// Optional derive map.
    #[serde(default)]
    pub derive: Option<serde_json::Value>,
}

/// Accessor for export schema endpoints.
pub struct ExportSchemasResource<'a> {
    pub(crate) client: &'a Client,
}

impl<'a> ExportSchemasResource<'a> {
    /// Lists export schemas as a flat array — this endpoint is not paginated.
    ///
    /// # Errors
    ///
    /// - [`crate::Error::Authentication`] on invalid credentials.
    /// - [`crate::Error::Network`] on transport failure.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # async fn example() -> ticksupply::Result<()> {
    /// let client = ticksupply::Client::new()?;
    /// for schema in client.export_schemas().list().await? {
    ///     println!("{}: {} (v{})", schema.id, schema.name, schema.version);
    /// }
    /// # Ok(()) }
    /// ```
    pub async fn list(&self) -> Result<Vec<ExportSchemaListItem>> {
        send::<_, ()>(
            self.client,
            reqwest::Method::GET,
            "/export-schemas",
            None,
            None,
            RequestOpts::default(),
        )
        .await
    }

    /// Retrieves a schema by ID, including its column definitions.
    ///
    /// # Errors
    ///
    /// - [`crate::Error::NotFound`] if no schema has this ID.
    /// - [`crate::Error::Authentication`] on invalid credentials.
    /// - [`crate::Error::Network`] on transport failure.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # async fn example() -> ticksupply::Result<()> {
    /// let client = ticksupply::Client::new()?;
    /// let schema = client.export_schemas().get("sch_abc").await?;
    /// println!("columns: {}", schema.columns);
    /// # Ok(()) }
    /// ```
    pub async fn get(&self, id: &str) -> Result<ExportSchemaWithVersion> {
        let path = format!("/export-schemas/{id}");
        send::<_, ()>(
            self.client,
            reqwest::Method::GET,
            &path,
            None,
            None,
            RequestOpts::default(),
        )
        .await
    }

    /// Deletes a user-owned schema.
    ///
    /// Built-in schemas cannot be deleted; attempting to delete one surfaces
    /// as [`crate::Error::NotFound`] since the account does not own it.
    ///
    /// # Errors
    ///
    /// - [`crate::Error::NotFound`] if no schema has this ID or the schema is built-in.
    /// - [`crate::Error::Authentication`] on invalid credentials.
    /// - [`crate::Error::Network`] on transport failure.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # async fn example() -> ticksupply::Result<()> {
    /// let client = ticksupply::Client::new()?;
    /// client.export_schemas().delete("sch_abc").await?;
    /// # Ok(()) }
    /// ```
    pub async fn delete(&self, id: &str) -> Result<()> {
        let path = format!("/export-schemas/{id}");
        send_empty::<()>(
            self.client,
            reqwest::Method::DELETE,
            &path,
            None,
            None,
            RequestOpts::default(),
        )
        .await
    }
}