Skip to content

Commit

Permalink
feat(sdk): temporal runtime (#413)
Browse files Browse the repository at this point in the history
  • Loading branch information
michael-0acf4 authored Sep 21, 2023
1 parent 8ade5d1 commit 1e61454
Show file tree
Hide file tree
Showing 10 changed files with 1,159 additions and 2 deletions.
775 changes: 775 additions & 0 deletions typegate/tests/runtimes/temporal/__snapshots__/temporal_test.ts.snap

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions typegate/tests/runtimes/temporal/temporal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from typegraph_next import t, typegraph, Policy, Graph
from typegraph_next.providers.temporal import TemporalRuntime


@typegraph()
def temporal(g: Graph):
public = Policy.public()
temporal = TemporalRuntime("<name>", "<host>")
arg = t.struct({"some_field": t.string()})

g.expose(
public,
start=temporal.start_workflow("<workflow_type>", arg),
query=temporal.query_workflow("<query_type>", arg),
signal=temporal.signal_workflow("<signal_name>", arg),
describe=temporal.describe_workflow(),
)
20 changes: 20 additions & 0 deletions typegate/tests/runtimes/temporal/temporal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright Metatype OÜ, licensed under the Elastic License 2.0.
// SPDX-License-Identifier: Elastic-2.0

import { Policy, t, typegraph } from "@typegraph/deno/src/mod.ts";
import { TemporalRuntime } from "@typegraph/deno/src/providers/temporal.ts";

typegraph("temporal", (g) => {
const pub = Policy.public();
const temporal = new TemporalRuntime("<name>", "<host>");
const arg = t.struct({ some_field: t.string() });

g.expose(
{
start: temporal.startWorkflow("<workflow_type>", arg).withPolicy(pub),
query: temporal.queryWorkflow("<query_type>", arg).withPolicy(pub),
signal: temporal.signalWorkflow("<signal_name>", arg).withPolicy(pub),
describe: temporal.describeWorkflow().withPolicy(pub),
},
);
});
17 changes: 17 additions & 0 deletions typegate/tests/runtimes/temporal/temporal_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright Metatype OÜ, licensed under the Elastic License 2.0.
// SPDX-License-Identifier: Elastic-2.0

import { Meta } from "../../utils/mod.ts";
import { MetaTest } from "../../utils/test.ts";

async function testSerialize(t: MetaTest, file: string) {
await t.should(`serialize typegraph ${file}`, async () => {
const tg = await Meta.cli("serialize", "--pretty", "-f", file);
await t.assertSnapshot(tg);
});
}

Meta.test("Typegraph using temporal", async (t) => {
await testSerialize(t, "runtimes/temporal/temporal.py");
await testSerialize(t, "runtimes/temporal/temporal.ts");
});
55 changes: 54 additions & 1 deletion typegraph/core/src/conversion/runtimes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::global_store::Store;
use crate::runtimes::prisma::{with_prisma_runtime, ConversionContext};
use crate::runtimes::{
DenoMaterializer, Materializer as RawMaterializer, PythonMaterializer, RandomMaterializer,
Runtime, WasiMaterializer,
Runtime, TemporalMaterializer, WasiMaterializer,
};
use crate::wit::core::RuntimeId;
use crate::wit::runtimes::{HttpMethod, MaterializerHttpRequest};
Expand All @@ -17,6 +17,7 @@ use common::typegraph::runtimes::http::HTTPRuntimeData;
use common::typegraph::runtimes::prisma::PrismaRuntimeData;
use common::typegraph::runtimes::python::PythonRuntimeData;
use common::typegraph::runtimes::random::RandomRuntimeData;
use common::typegraph::runtimes::temporal::TemporalRuntimeData;
use common::typegraph::runtimes::wasmedge::WasmEdgeRuntimeData;
use common::typegraph::runtimes::KnownRuntime;
use common::typegraph::{runtimes::TGRuntime, Effect, EffectType, Materializer};
Expand Down Expand Up @@ -287,6 +288,53 @@ impl MaterializerConverter for WasiMaterializer {
}
}

impl MaterializerConverter for TemporalMaterializer {
fn convert(
&self,
c: &mut TypegraphContext,
s: &Store,
runtime_id: RuntimeId,
effect: WitEffect,
) -> Result<Materializer> {
use crate::runtimes::TemporalMaterializer::*;
let runtime = c.register_runtime(s, runtime_id)?;
let (data, name) = match self {
Start { workflow_type } => {
let data = serde_json::from_value(json!({
"workflow_type": workflow_type,
}))
.unwrap();
(data, "start_workflow".to_string())
}
Signal { signal_name } => {
let data = serde_json::from_value(json!({
"signal_name": signal_name,
}))
.unwrap();
(data, "signal_workflow".to_string())
}
Query { query_type } => {
let data = serde_json::from_value(json!({
"query_type": query_type,
}))
.unwrap();
(data, "query_workflow".to_string())
}
Describe => {
let data = serde_json::from_value(json!({})).unwrap();
(data, "describe_workflow".to_string())
}
};

Ok(Materializer {
name,
runtime,
effect: effect.into(),
data,
})
}
}

pub fn convert_materializer(
c: &mut TypegraphContext,
s: &Store,
Expand Down Expand Up @@ -386,5 +434,10 @@ pub fn convert_runtime(
},
)))
}
Runtime::Temporal(d) => Ok(TGRuntime::Known(Temporal(TemporalRuntimeData {
name: d.name.clone(),
host: d.host.clone(),
}))
.into()),
}
}
29 changes: 28 additions & 1 deletion typegraph/core/src/runtimes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,18 @@ pub mod graphql;
pub mod prisma;
pub mod python;
pub mod random;
pub mod temporal;
pub mod wasi;

use crate::conversion::runtimes::MaterializerConverter;
use crate::global_store::{with_store, with_store_mut, Store};
use crate::runtimes::prisma::with_prisma_runtime;
use crate::t;
use crate::t::{self};
use crate::wit::core::{RuntimeId, TypeId as CoreTypeId};
use crate::wit::runtimes::{
self as wit, BaseMaterializer, Error as TgError, GraphqlRuntimeData, HttpRuntimeData,
MaterializerHttpRequest, PrismaLinkData, PrismaRuntimeData, RandomRuntimeData,
TemporalOperationData, TemporalRuntimeData,
};
use crate::{typegraph::TypegraphContext, wit::runtimes::Effect as WitEffect};
use enum_dispatch::enum_dispatch;
Expand All @@ -26,6 +28,8 @@ use self::prisma::relationship::prisma_link;
use self::prisma::{PrismaMaterializer, PrismaRuntimeContext};
pub use self::python::PythonMaterializer;
pub use self::random::RandomMaterializer;
use self::temporal::temporal_operation;
pub use self::temporal::TemporalMaterializer;
pub use self::wasi::WasiMaterializer;

type Result<T, E = TgError> = std::result::Result<T, E>;
Expand All @@ -39,6 +43,7 @@ pub enum Runtime {
Random(RandomRuntimeData),
WasmEdge,
Prisma(PrismaRuntimeData, Box<PrismaRuntimeContext>),
Temporal(TemporalRuntimeData),
}

#[derive(Debug)]
Expand Down Expand Up @@ -104,6 +109,14 @@ impl Materializer {
data: data.into(),
}
}

fn temporal(runtime_id: RuntimeId, data: TemporalMaterializer, effect: wit::Effect) -> Self {
Self {
runtime_id,
effect,
data: data.into(),
}
}
}

#[derive(Debug)]
Expand All @@ -116,6 +129,7 @@ pub enum MaterializerData {
Random(RandomMaterializer),
WasmEdge(WasiMaterializer),
Prisma(PrismaMaterializer),
Temporal(TemporalMaterializer),
}

// impl From<DenoMaterializer> for MaterializerData {
Expand Down Expand Up @@ -398,4 +412,17 @@ impl wit::Runtimes for crate::Lib {
}
Ok(builder.build()?.into())
}

fn register_temporal_runtime(data: TemporalRuntimeData) -> Result<RuntimeId, wit::Error> {
Ok(with_store_mut(|s| {
s.register_runtime(Runtime::Temporal(data))
}))
}

fn generate_temporal_operation(
runtime: RuntimeId,
data: TemporalOperationData,
) -> Result<CoreTypeId, wit::Error> {
temporal_operation(runtime, data)
}
}
85 changes: 85 additions & 0 deletions typegraph/core/src/runtimes/temporal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0.
// SPDX-License-Identifier: MPL-2.0

use super::Materializer;
use crate::errors::Result;
use crate::global_store::with_store_mut;
use crate::t;
use crate::t::TypeBuilder;
use crate::wit::core::TypeId;
use crate::wit::runtimes::Effect as WitEffect;
use crate::wit::runtimes::{RuntimeId, TemporalOperationData, TemporalOperationType};

#[derive(Debug)]
pub enum TemporalMaterializer {
Start { workflow_type: String },
Signal { signal_name: String },
Query { query_type: String },
Describe,
}

pub fn temporal_operation(runtime: RuntimeId, data: TemporalOperationData) -> Result<TypeId> {
let mut inp = t::struct_();
let (effect, mat_data) = match data.operation {
TemporalOperationType::StartWorkflow => {
let arg = data
.func_arg
.ok_or("workflow arg is undefined".to_string())?;
let mat_arg = data
.mat_arg
.ok_or("materializer arg is undefined".to_string())?;
inp.prop("workflow_id", t::string().build()?);
inp.prop("args", t::array(arg.into()).build()?);
(
WitEffect::Create(false),
TemporalMaterializer::Start {
workflow_type: mat_arg,
},
)
}
TemporalOperationType::SignalWorkflow => {
let arg = data
.func_arg
.ok_or("workflow arg is undefined".to_string())?;
let mat_arg = data
.mat_arg
.ok_or("materializer arg is undefined".to_string())?;
inp.prop("workflow_id", t::string().build()?);
inp.prop("run_id", t::string().build()?);
inp.prop("args", t::array(arg.into()).build()?);
(
WitEffect::Update(false),
TemporalMaterializer::Signal {
signal_name: mat_arg,
},
)
}
TemporalOperationType::QueryWorkflow => {
let arg = data
.func_arg
.ok_or("workflow arg is undefined".to_string())?;
let mat_arg = data
.mat_arg
.ok_or("materializer arg is undefined".to_string())?;
inp.prop("workflow_id", t::string().build()?);
inp.prop("run_id", t::string().build()?);
inp.prop("args", t::array(arg.into()).build()?);
(
WitEffect::None,
TemporalMaterializer::Query {
query_type: mat_arg,
},
)
}
TemporalOperationType::DescribeWorkflow => {
inp.prop("workflow_id", t::string().build()?);
inp.prop("run_id", t::string().build()?);
(WitEffect::None, TemporalMaterializer::Describe)
}
};

let mat = Materializer::temporal(runtime, mat_data, effect);
let mat_id = with_store_mut(|s| s.register_materializer(mat));
let fn_id = t::func(inp.build()?, t::string().build()?, mat_id)?;
Ok(fn_id.into())
}
22 changes: 22 additions & 0 deletions typegraph/core/wit/typegraph.wit
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,28 @@ interface runtimes {
prisma-delete-one: func(runtime: runtime-id, model: type-id) -> result<type-id, error>
prisma-delete-many: func(runtime: runtime-id, model: type-id) -> result<type-id, error>
prisma-link: func(data: prisma-link-data) -> result<type-id, error>

// temporal
record temporal-runtime-data {
name: string,
host: string,
}

variant temporal-operation-type {
start-workflow,
signal-workflow,
query-workflow,
describe-workflow
}

record temporal-operation-data {
mat-arg: option<string>,
func-arg: option<type-id>,
operation: temporal-operation-type,
}

register-temporal-runtime: func(data: temporal-runtime-data) -> result<runtime-id, error>
generate-temporal-operation: func(runtime: runtime-id, data: temporal-operation-data) -> result<type-id, error>
}


Expand Down
Loading

0 comments on commit 1e61454

Please sign in to comment.