diff --git a/_project/api/_src/Usecases/Graph.Controllers.ts b/_project/api/_src/Usecases/Graph.Controllers.ts index d7a8bb54..6afe5523 100644 --- a/_project/api/_src/Usecases/Graph.Controllers.ts +++ b/_project/api/_src/Usecases/Graph.Controllers.ts @@ -6,7 +6,7 @@ import { GraphRsc } from "@effect-app-boilerplate/resources" import type { GraphMutationResponse } from "@effect-app-boilerplate/resources/Graph/Mutation" import type { GraphQueryRequest, GraphQueryResponse } from "@effect-app-boilerplate/resources/Graph/Query" import { dropUndefined } from "@effect-app/core/utils" -import { makeRequestId, RequestContext } from "@effect-app/infra/RequestContext" +import { RequestContext, RequestId } from "@effect-app/infra/RequestContext" import { RequestContextContainer } from "@effect-app/infra/services/RequestContextContainer" import type { CTX } from "api/lib/routing.js" import BlogControllers from "./Blog.Controllers.js" @@ -25,24 +25,26 @@ function request<Key extends string>( ) => { const q = req[name] return q - ? Effect.gen(function*($) { - yield* $(RequestContextContainer.flatMap(_ => - _.update(ctx => - RequestContext.inherit(ctx, { - id: makeRequestId(), - locale: ctx.locale, - name: ReasonableString(name) // TODO: Use name from handler.Request - }) - ) - )) + ? Effect + .gen(function*($) { + yield* $(RequestContextContainer.flatMap((_) => + _.update((ctx) => + RequestContext.inherit(ctx, { + id: RequestId.make(), + locale: ctx.locale, + name: ReasonableString(name) // TODO: Use name from handler.Request + }) + ) + )) - const ctx = yield* $(RequestContextContainer.get) + const ctx = yield* $(RequestContextContainer.get) - const r = yield* $( - handler(q.input ?? {}, { ...context, context: ctx }) - ) - return r - })["|>"](Effect.either) + const r = yield* $( + handler(q.input ?? {}, { ...context, context: ctx }) + ) + return r + }) + ["|>"](Effect.either) : NoResponse } } @@ -89,17 +91,20 @@ function mutation<Key extends string>( resultQuery?: (inp: A, ctx: CTX) => Effect<R2, E2, A2> ) => { const q = req[name] - return f(name, handler).flatMap(x => + return f(name, handler).flatMap((x) => !x ? Effect(x) : x.isLeft() - ? Effect(x) + ? Effect(Either.left(x.left)) : (q?.query - ? Effect.allPar({ - query: Query.flatMap(_ => _(q.query!, ctx)), - result: resultQuery ? resultQuery(x.right, ctx) : emptyResponse - }).map(({ query, result }) => ({ ...query, result })) // TODO: Replace $ variables in the query parameters baed on mutation output! - : emptyResponse).map(query => Either(query ? { query, response: x.right } : { response: x.right })) + ? Effect + .allPar({ + query: Query.flatMap((_) => _(q.query!, ctx)), + result: resultQuery ? resultQuery(x.right, ctx) : emptyResponse + }) + .map(({ query, result }) => ({ ...query, result })) // TODO: Replace $ variables in the query parameters baed on mutation output! + : emptyResponse) + .map((query) => Either(query ? { query, response: x.right } : { response: x.right })) ) } } @@ -116,8 +121,10 @@ const Mutation = graph.matchMutation.withEffect( "CreatePost", blogPostControllers.CreatePost.h, (id, ctx) => - blogPostControllers.FindPost.h({ id }, ctx) - .flatMap(x => (!x ? Effect.die("Post went away?") : Effect(x))) + blogPostControllers + .FindPost + .h({ id }, ctx) + .flatMap((x) => (!x ? Effect.die("Post went away?") : Effect(x))) ) // UpdatePurchaseOrder: handle("UpdatePurchaseOrder", UpdatePurchaseOrder.h, () => // FindPurchaseOrder.h(req.UpdatePurchaseOrder!.input).flatMap(x => diff --git a/_project/resources/_src/Graph/Mutation.ts b/_project/resources/_src/Graph/Mutation.ts index 4993e23e..1f19ced0 100644 --- a/_project/resources/_src/Graph/Mutation.ts +++ b/_project/resources/_src/Graph/Mutation.ts @@ -14,9 +14,8 @@ const makeMutationInput_ = makeMutationInput(GraphQueryRequest.Api.props) @allowRoles("user") export class GraphMutationRequest extends Post("/graph/mutate")<GraphMutationRequest>()( { - CreatePost: optProp( - makeMutationInput_(CreatePost.CreatePostRequest) - ) + CreatePost: makeMutationInput_(CreatePost.CreatePostRequest) + .optional // UpdatePurchaseOrder: optProp( // makeMutationInput_(PurchaseOrders.Update.UpdatePurchaseOrderRequest) // ) @@ -25,7 +24,7 @@ export class GraphMutationRequest extends Post("/graph/mutate")<GraphMutationReq const PostResult = props({ ...GraphQueryResponse.Api.props, - result: optProp(BlogPost) + result: BlogPost.optional }) @useClassFeaturesForSchema @@ -33,21 +32,20 @@ export class GraphMutationResponse extends Model<GraphMutationResponse>()({ // TODO: Support guaranteed optional sub-queries, like on Create/Update of PO // guarantee an optional return of PurchaseOrder // first must enable PO cache for guarantee. - CreatePost: optProp( - either( - MutationErrors, - props({ - response: prop(CreatePost.CreatePostResponse), - query: optProp(PostResult) - }) - ) + CreatePost: either( + MutationErrors, + props({ + response: CreatePost.CreatePostResponse, + query: PostResult.optional + }) ) + .optional // UpdatePurchaseOrder: optProp( // either( // MutationErrors, // props({ - // response: optProp(Void), - // query: optProp(POResult) + // response: Void.optional, + // query: POResult.optional // }) // ) // ) diff --git a/_project/resources/_src/Graph/Query.ts b/_project/resources/_src/Graph/Query.ts index 69c4c52e..be6c46d8 100644 --- a/_project/resources/_src/Graph/Query.ts +++ b/_project/resources/_src/Graph/Query.ts @@ -1,6 +1,6 @@ import { either } from "@effect-app/prelude/schema" +import * as BlogRsc from "../Blog.js" import { QueryErrors } from "../errors.js" -import { BlogRsc } from "../index.js" import { makeInput } from "./utils.js" @useClassFeaturesForSchema @@ -17,8 +17,8 @@ export class GraphQueryRequest extends Post("/graph/query")<GraphQueryRequest>() // ), // AllMeTasks: optProp(makeInput(Me.Tasks.AllMeTasksRequest, true)), - FindBlogPost: optProp(makeInput(BlogRsc.FindPost.FindPostRequest)), - GetAllBlogPosts: optProp(makeInput(BlogRsc.GetPosts.GetPostsRequest)) + FindBlogPost: makeInput(BlogRsc.FindPost.FindPostRequest).optional, + GetAllBlogPosts: makeInput(BlogRsc.GetPosts.GetPostsRequest).optional }) {} @useClassFeaturesForSchema @@ -33,7 +33,5 @@ export class GraphQueryResponse extends Model<GraphQueryResponse>()({ // ), // AllMeTasks: optProp(either(QueryErrors, Me.Tasks.AllMeTasksResponse)), - FindBlogPost: optProp( - either(QueryErrors, BlogRsc.FindPost.FindPostResponse) - ) + FindBlogPost: either(QueryErrors, BlogRsc.FindPost.FindPostResponse).optional }) {} diff --git a/_project/resources/_src/Graph/utils.ts b/_project/resources/_src/Graph/utils.ts index 91ddf17a..5037f16a 100644 --- a/_project/resources/_src/Graph/utils.ts +++ b/_project/resources/_src/Graph/utils.ts @@ -3,21 +3,21 @@ import type { Property, PropertyRecord, SchemaAny, SchemaProperties } from "@eff export function makeInput<Self extends SchemaAny>( a: Self ): SchemaProperties<{ - input: Property<Self, "required", None, None> + input: Property<Self, "required", None<any>, None<any>> }> export function makeInput<Self extends SchemaAny>( a: Self, noInput: true ): SchemaProperties<{ - input: Property<Self, "optional", None, None> + input: Property<Self, "optional", None<any>, None<any>> }> export function makeInput<Self extends SchemaAny>(a: Self, noInput?: boolean): any { - return props(noInput ? { input: optProp(a) } : { input: prop(a) }) + return props(noInput ? { input: a.optional } : { input: a }) } export function makeMutationInput<Props extends PropertyRecord>(baseSchemaProps: Props) { return <Self extends SchemaAny>(a: Self) => { - const query = props({ ...baseSchemaProps, result: optProp(bool) }) - return props({ input: prop(a), query: optProp(query) }) + const query = props({ ...baseSchemaProps, result: bool.optional }) + return props({ input: a, query: query.optional }) } }