Work
This commit is contained in:
@@ -1,9 +1,9 @@
|
|||||||
import { Layer } from "effect"
|
import { Layer } from "effect"
|
||||||
import { TodoRepositoryLive } from "./TodoRepository"
|
import { TodoRepository } from "./TodoRepository"
|
||||||
|
|
||||||
|
|
||||||
export const ServicesLive = Layer.mergeAll(
|
export const ServicesLive = Layer.mergeAll(
|
||||||
TodoRepositoryLive
|
TodoRepository.Live
|
||||||
)
|
)
|
||||||
|
|
||||||
export interface Services extends Layer.Layer.Success<typeof ServicesLive> {}
|
export interface Services extends Layer.Layer.Success<typeof ServicesLive> {}
|
||||||
|
|||||||
@@ -5,11 +5,13 @@ import crypto from "node:crypto"
|
|||||||
|
|
||||||
export class TodoRepository extends Context.Tag("TodoRepository")<TodoRepository, TodoRepositoryService>() {}
|
export class TodoRepository extends Context.Tag("TodoRepository")<TodoRepository, TodoRepositoryService>() {}
|
||||||
|
|
||||||
export const TodoRepositoryLive = Layer.effect(TodoRepository,
|
export module TodoRepository {
|
||||||
SubscriptionRef.make(Array.empty<Todo & { id: Option.Some<string> }>()).pipe(
|
export const Live = Layer.effect(TodoRepository,
|
||||||
Effect.map(ref => new TodoRepositoryService(ref))
|
SubscriptionRef.make(Array.empty<Todo & { id: Option.Some<string> }>()).pipe(
|
||||||
|
Effect.map(ref => new TodoRepositoryService(ref))
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
|
|
||||||
|
|
||||||
export class TodoRepositoryService {
|
export class TodoRepositoryService {
|
||||||
@@ -17,13 +19,13 @@ export class TodoRepositoryService {
|
|||||||
readonly todos: SubscriptionRef.SubscriptionRef<(Todo & { id: Option.Some<string> })[]>
|
readonly todos: SubscriptionRef.SubscriptionRef<(Todo & { id: Option.Some<string> })[]>
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
get(id: string) {
|
getByID(id: string) {
|
||||||
return this.todos.get.pipe(
|
return this.todos.get.pipe(
|
||||||
Effect.map(Array.findFirst(todo => Equal.equals(todo.id.value, id)))
|
Effect.map(Array.findFirst(todo => Equal.equals(todo.id.value, id)))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
getIndex(id: string) {
|
getIndexByID(id: string) {
|
||||||
return this.todos.get.pipe(
|
return this.todos.get.pipe(
|
||||||
Effect.map(Array.findFirstIndex(todo => Equal.equals(todo.id.value, id)))
|
Effect.map(Array.findFirstIndex(todo => Equal.equals(todo.id.value, id)))
|
||||||
)
|
)
|
||||||
@@ -34,12 +36,14 @@ export class TodoRepositoryService {
|
|||||||
if (Option.isSome(todo.id))
|
if (Option.isSome(todo.id))
|
||||||
return yield* Effect.fail(new TodoHasID({ todo }))
|
return yield* Effect.fail(new TodoHasID({ todo }))
|
||||||
|
|
||||||
yield* Ref.update(this.todos, todos =>
|
const id: string = crypto.randomUUID()
|
||||||
Array.append(todos, new Todo({
|
|
||||||
...todo,
|
yield* Ref.update(this.todos, Array.append(new Todo({
|
||||||
id: Option.some(crypto.randomUUID()),
|
...todo,
|
||||||
}) as Todo & { id: Option.Some<string> })
|
id: Option.some(id),
|
||||||
)
|
}) as Todo & { id: Option.Some<string> }))
|
||||||
|
|
||||||
|
return id
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +53,7 @@ export class TodoRepositoryService {
|
|||||||
return yield* Effect.fail(new TodoHasNoID({ todo }))
|
return yield* Effect.fail(new TodoHasNoID({ todo }))
|
||||||
|
|
||||||
yield* Ref.update(this.todos, Array.replace(
|
yield* Ref.update(this.todos, Array.replace(
|
||||||
yield* yield* this.getIndex(todo.id.value),
|
yield* yield* this.getIndexByID(todo.id.value),
|
||||||
todo as Todo & { id: Option.Some<string> },
|
todo as Todo & { id: Option.Some<string> },
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
@@ -61,7 +65,7 @@ export class TodoRepositoryService {
|
|||||||
return yield* Effect.fail(new TodoHasNoID({ todo }))
|
return yield* Effect.fail(new TodoHasNoID({ todo }))
|
||||||
|
|
||||||
yield* Ref.update(this.todos, Array.remove(
|
yield* Ref.update(this.todos, Array.remove(
|
||||||
yield* yield* this.getIndex(todo.id.value)
|
yield* yield* this.getIndexByID(todo.id.value)
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { BunRuntime } from "@effect/platform-bun"
|
import { BunRuntime } from "@effect/platform-bun"
|
||||||
import { Todo } from "@todo-tests/common/data"
|
import { Todo } from "@todo-tests/common/data"
|
||||||
import { Identifiable } from "@todo-tests/common/traits"
|
import { Identifiable } from "@todo-tests/common/traits"
|
||||||
import { Array, Duration, Effect, Layer, Option, Stream } from "effect"
|
import { Array, Effect, Layer, Option, Stream } from "effect"
|
||||||
import { ServicesLive } from "./Services"
|
import { ServicesLive } from "./Services"
|
||||||
import { TodoRepository, createDefaultTodos } from "./TodoRepository"
|
import { TodoRepository, createDefaultTodos } from "./TodoRepository"
|
||||||
import { ExpressApp } from "./express/ExpressApp"
|
import { ExpressApp } from "./express/ExpressApp"
|
||||||
@@ -41,10 +41,10 @@ const watchTodoChanges = Effect.gen(function*() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const main = Effect.gen(function*() {
|
const main = Effect.gen(function*() {
|
||||||
const watcher = yield* Effect.fork(watchTodoChanges)
|
// const watcher = yield* Effect.fork(watchTodoChanges)
|
||||||
yield* createDefaultTodos
|
yield* createDefaultTodos
|
||||||
|
|
||||||
const todos = yield* TodoRepository
|
// const todos = yield* TodoRepository
|
||||||
|
|
||||||
// const secondTodo = yield* yield* todos.todos.get.pipe(
|
// const secondTodo = yield* yield* todos.todos.get.pipe(
|
||||||
// Effect.map(Array.get(1))
|
// Effect.map(Array.get(1))
|
||||||
@@ -55,17 +55,17 @@ const main = Effect.gen(function*() {
|
|||||||
// })
|
// })
|
||||||
// yield* todos.update(secondTodoModified)
|
// yield* todos.update(secondTodoModified)
|
||||||
|
|
||||||
yield* todos.add(new Todo({
|
// yield* todos.add(new Todo({
|
||||||
id: Option.none(),
|
// id: Option.none(),
|
||||||
title: "Put the dishes in the dishwasher",
|
// title: "Put the dishes in the dishwasher",
|
||||||
content: "Lorem ipsum",
|
// content: "Lorem ipsum",
|
||||||
due: Option.none(),
|
// due: Option.none(),
|
||||||
completed: false,
|
// completed: false,
|
||||||
createdAt: new Date(),
|
// createdAt: new Date(),
|
||||||
updatedAt: new Date(),
|
// updatedAt: new Date(),
|
||||||
})).pipe(
|
// })).pipe(
|
||||||
Effect.delay(Duration.seconds(1))
|
// Effect.delay(Duration.seconds(1))
|
||||||
)
|
// )
|
||||||
|
|
||||||
// yield* Fiber.join(watcher)
|
// yield* Fiber.join(watcher)
|
||||||
yield* Layer.launch(ServerLive)
|
yield* Layer.launch(ServerLive)
|
||||||
|
|||||||
@@ -11,24 +11,41 @@ export const todosRouter = Effect.gen(function*() {
|
|||||||
const procedure = yield* RPCProcedureBuilder
|
const procedure = yield* RPCProcedureBuilder
|
||||||
|
|
||||||
return t.router({
|
return t.router({
|
||||||
all: procedure.query(({ ctx }) => ctx.run(Effect.gen(function*() {
|
all: procedure
|
||||||
const todos = yield* TodoRepository
|
.query(({ ctx }) => ctx.run(Effect.gen(function*() {
|
||||||
|
const todos = yield* TodoRepository
|
||||||
|
|
||||||
return yield* S.encode(S.Array(JsonifiableTodo))(
|
return yield* S.encode(S.Array(JsonifiableTodo))(
|
||||||
yield* todos.todos.get
|
yield* todos.todos.get
|
||||||
)
|
)
|
||||||
}))),
|
}))),
|
||||||
|
|
||||||
get: procedure
|
getByID: procedure
|
||||||
.input(S.decodeUnknownSync(
|
.input(S.decodeUnknownPromise(S.String))
|
||||||
S.Struct({ id: S.String })
|
|
||||||
))
|
|
||||||
.query(({ ctx, input }) => ctx.run(Effect.gen(function*() {
|
.query(({ ctx, input }) => ctx.run(Effect.gen(function*() {
|
||||||
const todos = yield* TodoRepository
|
const todos = yield* TodoRepository
|
||||||
|
|
||||||
return yield* S.encode(S.OptionFromNullOr(JsonifiableTodo))(
|
return yield* S.encode(S.OptionFromNullOr(JsonifiableTodo))(
|
||||||
yield* todos.get(input.id)
|
yield* todos.getByID(input)
|
||||||
)
|
)
|
||||||
}))),
|
}))),
|
||||||
|
|
||||||
|
add: procedure
|
||||||
|
.input(S.decodeUnknownPromise(JsonifiableTodo))
|
||||||
|
.mutation(({ ctx, input }) => ctx.run(TodoRepository.pipe(
|
||||||
|
Effect.flatMap(todos => todos.add(input))
|
||||||
|
))),
|
||||||
|
|
||||||
|
update: procedure
|
||||||
|
.input(S.decodeUnknownPromise(JsonifiableTodo))
|
||||||
|
.mutation(({ ctx, input }) => ctx.run(TodoRepository.pipe(
|
||||||
|
Effect.flatMap(todos => todos.update(input))
|
||||||
|
))),
|
||||||
|
|
||||||
|
remove: procedure
|
||||||
|
.input(S.decodeUnknownPromise(JsonifiableTodo))
|
||||||
|
.mutation(({ ctx, input }) => ctx.run(TodoRepository.pipe(
|
||||||
|
Effect.flatMap(todos => todos.remove(input))
|
||||||
|
))),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user