This commit is contained in:
Julien Valverdé
2024-07-12 03:08:03 +02:00
parent 4d4ba6e5f2
commit 2fcf809311
4 changed files with 4 additions and 49 deletions

View File

@@ -0,0 +1,138 @@
import { Todo, type IdentifiedTodo } from "@todo-tests/common/data"
import { Chunk, Context, Data, Effect, Equal, Layer, Option, Order, Ref, SubscriptionRef, flow } from "effect"
import crypto from "node:crypto"
export class TodoRepository extends Context.Tag("TodoRepository")<TodoRepository, TodoRepositoryService>() {}
export module TodoRepository {
export const Live = Layer.effect(TodoRepository,
SubscriptionRef.make(Chunk.empty<IdentifiedTodo>()).pipe(
Effect.map(ref => new TodoRepositoryService(ref))
)
)
}
export class TodoRepositoryService {
constructor(
readonly todos: SubscriptionRef.SubscriptionRef<Chunk.Chunk<IdentifiedTodo>>
) {}
getByID(id: string) {
return this.todos.get.pipe(
Effect.map(Chunk.findFirst(todo => Equal.equals(todo.id.value, id)))
)
}
getIndexByID(id: string) {
return this.todos.get.pipe(
Effect.map(Chunk.findFirstIndex(todo => Equal.equals(todo.id.value, id)))
)
}
add(todo: Todo) {
return Effect.gen(this, function*() {
if (Option.isSome(todo.id))
return yield* Effect.fail(new TodoHasID({ todo }))
const id: string = crypto.randomUUID()
yield* Ref.update(this.todos, flow(
Chunk.append(new Todo({
...todo,
id: Option.some(id),
}) as IdentifiedTodo),
sortTodos,
updateTodosOrder,
))
return id
})
}
update(todo: Todo) {
return Effect.gen(this, function*() {
if (Option.isNone(todo.id))
return yield* Effect.fail(new TodoHasNoID({ todo }))
yield* Ref.update(this.todos, flow(
Chunk.replace(
yield* yield* this.getIndexByID(todo.id.value),
todo as IdentifiedTodo,
),
sortTodos,
updateTodosOrder,
))
})
}
remove(todo: Todo) {
return Effect.gen(this, function*() {
if (Option.isNone(todo.id))
return yield* Effect.fail(new TodoHasNoID({ todo }))
yield* Ref.update(this.todos, flow(
Chunk.remove(
yield* yield* this.getIndexByID(todo.id.value)
),
updateTodosOrder,
))
})
}
}
const sortTodos = Chunk.sort<IdentifiedTodo>(
Order.mapInput(Order.number, todo => todo.order)
)
const updateTodosOrder = Chunk.map<
Chunk.Chunk<IdentifiedTodo>,
IdentifiedTodo
>((todo, order) =>
new Todo({ ...todo, order }, { disableValidation: true }) as IdentifiedTodo
)
export class TodoHasID extends Data.TaggedError("TodoHasID")<{ todo: Todo }> {}
export class TodoHasNoID extends Data.TaggedError("TodoHasNoID")<{ todo: Todo }> {}
export const createDefaultTodos = Effect.gen(function*() {
const todos = yield* TodoRepository
yield* todos.add(new Todo({
id: Option.none(),
order: 0,
content: "Sort the socks",
due: Option.none(),
completed: false,
createdAt: new Date(),
updatedAt: new Date(),
}))
yield* todos.add(new Todo({
id: Option.none(),
order: 1,
content: "Sort the dog",
due: Option.none(),
completed: false,
createdAt: new Date(),
updatedAt: new Date(),
}))
yield* todos.add(new Todo({
id: Option.none(),
order: 2,
content: "Sort the car",
due: Option.none(),
completed: false,
createdAt: new Date(),
updatedAt: new Date(),
}))
})