Skip to content

Commit

Permalink
Add Graph support
Browse files Browse the repository at this point in the history
  • Loading branch information
patroza committed Feb 11, 2023
1 parent 41f4cc4 commit 8f313a8
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 0 deletions.
54 changes: 54 additions & 0 deletions _project/resources/_src/Graph/Mutation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { BlogPost } from "@effect-app-boilerplate/models/Blog"
import { either } from "@effect-app/prelude/schema"
import { CreatePost } from "../Blog.js"
import { MutationErrors } from "../errors.js"
import { GraphQueryRequest, GraphQueryResponse } from "./Query.js"
import { makeMutationInput } from "./utils.js"

const makeMutationInput_ = makeMutationInput(GraphQueryRequest.Api.props)

// TODO: Add The follow-up Graph Query
// - parse inputs, when string and starts with $, take from mutation output.
@useClassNameForSchema
@allowAnonymous
@allowRoles("user")
export class GraphMutationRequest extends Post("/graph/mutate")<GraphMutationRequest>()(
{
CreatePost: optProp(
makeMutationInput_(CreatePost.CreatePostRequest)
)
// UpdatePurchaseOrder: optProp(
// makeMutationInput_(PurchaseOrders.Update.UpdatePurchaseOrderRequest)
// )
}
) {}

const PostResult = props({
...GraphQueryResponse.Api.props,
result: optProp(BlogPost)
})

@useClassNameForSchema
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)
})
)
)
// UpdatePurchaseOrder: optProp(
// either(
// MutationErrors,
// props({
// response: optProp(Void),
// query: optProp(POResult)
// })
// )
// )
}) {}
39 changes: 39 additions & 0 deletions _project/resources/_src/Graph/Query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { either } from "@effect-app/prelude/schema"
import { QueryErrors } from "../errors.js"
import { BlogRsc } from "../index.js"
import { makeInput } from "./utils.js"

@useClassNameForSchema
@allowAnonymous
@allowRoles("user")
export class GraphQueryRequest extends Post("/graph/query")<GraphQueryRequest>()({
// AllMe: optProp(makeInput(Me.All.GetMeRequest, true)),
// AllMeEventlog: optProp(makeInput(Me.Eventlog.AllMeEventlogRequest, true)),
// AllMeChangeRequests: optProp(
// makeInput(Me.ChangeRequests.AllMeChangeRequestsRequest, true)
// ),
// AllMeCommentActivity: optProp(
// makeInput(Me.CommentActivity.AllMeCommentActivityRequest, true)
// ),
// AllMeTasks: optProp(makeInput(Me.Tasks.AllMeTasksRequest, true)),

FindBlogPost: optProp(makeInput(BlogRsc.FindPost.FindPostRequest)),
GetAllBlogPosts: optProp(makeInput(BlogRsc.GetPosts.GetPostsRequest))
}) {}

@useClassNameForSchema
export class GraphQueryResponse extends Model<GraphQueryResponse>()({
// AllMe: optProp(either(QueryErrors, Me.All.GetMeResponse)),
// AllMeEventlog: optProp(either(QueryErrors, Me.Eventlog.AllMeEventlogResponse)),
// AllMeChangeRequests: optProp(
// either(QueryErrors, Me.ChangeRequests.AllMeChangeRequestsResponse)
// ),
// AllMeCommentActivity: optProp(
// either(QueryErrors, Me.CommentActivity.AllMeCommentActivityResponse)
// ),
// AllMeTasks: optProp(either(QueryErrors, Me.Tasks.AllMeTasksResponse)),

FindBlogPost: optProp(
either(QueryErrors, BlogRsc.FindPost.FindPostResponse)
)
}) {}
23 changes: 23 additions & 0 deletions _project/resources/_src/Graph/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { Property, PropertyRecord, SchemaAny, SchemaProperties } from "@effect-app/prelude/schema"

export function makeInput<Self extends SchemaAny>(
a: Self
): SchemaProperties<{
input: Property<Self, "required", None, None>
}>
export function makeInput<Self extends SchemaAny>(
a: Self,
noInput: true
): SchemaProperties<{
input: Property<Self, "optional", None, None>
}>
export function makeInput<Self extends SchemaAny>(a: Self, noInput?: boolean): any {
return props(noInput ? { input: optProp(a) } : { input: prop(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) })
}
}
70 changes: 70 additions & 0 deletions _project/resources/_src/errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
@useClassNameForSchema
export class NotFoundError extends Model<NotFoundError>()({
_tag: prop(literal("NotFoundError")),
message: prop(string)
}) {}

@useClassNameForSchema
export class InvalidStateError extends Model<InvalidStateError>()({
_tag: prop(literal("InvalidStateError")),
message: prop(string)
}) {}

@useClassNameForSchema
export class ValidationError extends Model<ValidationError>()({
_tag: prop(literal("ValidationError")),
errors: prop(array(unknown)) // meh
}) {}

@useClassNameForSchema
export class NotLoggedInError extends Model<NotLoggedInError>()({
_tag: prop(literal("NotLoggedInError"))
}) {}

@useClassNameForSchema
export class UnauthorizedError extends Model<UnauthorizedError>()({
_tag: prop(literal("UnauthorizedError"))
}) {}

@useClassNameForSchema
export class OptimisticConcurrencyException extends Model<OptimisticConcurrencyException>()(
{
_tag: prop(literal("OptimisticConcurrencyException"))
}
) {}

const MutationOnlyErrors = {
InvalidStateError,
OptimisticConcurrencyException
}

const GeneralErrors = {
NotFoundError,
NotLoggedInError,
UnauthorizedError,
ValidationError
}

export const SupportedErrors = union({
...MutationOnlyErrors,
...GeneralErrors
})
["|>"](named("SupportedErrors"))
["|>"](withDefaults)
export type SupportedErrors = ParsedShapeOf<typeof SupportedErrors>

// ideal?
// export const QueryErrors = union({ ...GeneralErrors })
// ["|>"](named("QueryErrors"))
// ["|>"](withDefaults)
// export type QueryErrors = ParsedShapeOf<typeof QueryErrors>
// export const MutationErrors = union({ ...GeneralErrors, ...GeneralErrors })
// ["|>"](named("MutationErrors"))
// ["|>"](withDefaults)

// export type MutationErrors = ParsedShapeOf<typeof MutationErrors>

export const MutationErrors = SupportedErrors
export const QueryErrors = SupportedErrors
export type MutationErrors = ParsedShapeOf<typeof MutationErrors>
export type QueryErrors = ParsedShapeOf<typeof QueryErrors>

0 comments on commit 8f313a8

Please sign in to comment.