use crate::resources::Pipeline;
use crate::schema::steps;
use crate::{Database, Processor};
use diesel::prelude::*;
use serde::{Deserialize, Serialize};
use std::convert::{AsRef, TryFrom, TryInto};
use std::error::Error;
#[derive(Clone, Debug, Deserialize, Serialize, Associations, Identifiable, Queryable)]
#[belongs_to(Pipeline)]
#[table_name = "steps"]
pub(crate) struct Step {
pub(crate) id: i32,
pub(crate) name: String,
pub(crate) description: Option<String>,
pub(crate) processor: serde_json::Value,
pub(crate) position: i32,
pub(crate) pipeline_id: i32,
}
impl Step {
pub(crate) fn processor(&self) -> Result<Processor, serde_json::Error> {
serde_json::from_value(self.processor.clone())
}
pub(crate) fn pipeline(&self, conn: &Database) -> QueryResult<Pipeline> {
use crate::schema::pipelines::dsl::*;
pipelines.filter(id.eq(self.pipeline_id)).first(&**conn)
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub(crate) struct NewStep<'a> {
name: &'a str,
description: Option<&'a str>,
processor: Processor,
position: i32,
}
impl<'a> NewStep<'a> {
pub(crate) const fn new(
name: &'a str,
description: Option<&'a str>,
processor: Processor,
position: i32,
) -> Self {
Self {
name,
description,
processor,
position,
}
}
pub(crate) fn add_to_pipeline(
self,
conn: &Database,
pipeline: &Pipeline,
) -> Result<(), Box<dyn Error>> {
use crate::schema::steps::dsl::*;
let values = (
name.eq(&self.name),
description.eq(&self.description),
processor.eq(serde_json::to_value(self.processor)?),
position.eq(self.position),
pipeline_id.eq(pipeline.id),
);
diesel::insert_into(steps)
.values(values)
.execute(&**conn)
.map(|_| ())
.map_err(Into::into)
}
}
pub(crate) mod graphql {
use super::*;
use crate::ProcessorInput;
use juniper::{object, FieldResult, GraphQLInputObject, ID};
#[derive(Clone, Debug, Deserialize, Serialize, GraphQLInputObject)]
pub(crate) struct CreateStepInput {
pub(crate) name: String,
pub(crate) description: Option<String>,
pub(crate) processor: ProcessorInput,
}
#[object(Context = Database)]
impl Step {
fn id() -> ID {
ID::new(self.id.to_string())
}
fn name() -> &str {
&self.name
}
fn description() -> Option<&str> {
self.description.as_ref().map(String::as_ref)
}
fn processor() -> FieldResult<Processor> {
self.processor().map_err(Into::into)
}
fn position() -> i32 {
self.position
}
fn pipeline(context: &Database) -> FieldResult<Option<Pipeline>> {
self.pipeline(context).map(Some).map_err(Into::into)
}
}
}
#[allow(clippy::cast_possible_wrap, clippy::cast_possible_truncation)]
impl<'a> TryFrom<(usize, &'a graphql::CreateStepInput)> for NewStep<'a> {
type Error = String;
fn try_from((index, input): (usize, &'a graphql::CreateStepInput)) -> Result<Self, String> {
Ok(Self::new(
&input.name,
input.description.as_ref().map(String::as_ref),
input.processor.clone().try_into()?,
index as i32,
))
}
}