TodoRepository work

This commit is contained in:
Julien Valverdé
2024-07-08 21:38:44 +02:00
parent 8f8c696e3a
commit e88a6f7b1c
3 changed files with 36 additions and 26 deletions

View File

@@ -1,6 +1,7 @@
import { Schema as S } from "@effect/schema" import { Schema as S } from "@effect/schema"
import { Jsonifiable, Kind, Tag } from "@thilawyn/thilalib/effect/schema" import { Jsonifiable, Kind, Tag } from "@thilawyn/thilalib/effect/schema"
import { Class } from "@thilawyn/thilalib/effect/schema/class" import { Class } from "@thilawyn/thilalib/effect/schema/class"
import type { Option } from "effect"
import type { Identifiable } from "../traits" import type { Identifiable } from "../traits"
@@ -22,6 +23,9 @@ export class Todo
implements Identifiable<"Todo", string> implements Identifiable<"Todo", string>
{} {}
export type IdentifiedTodo = Todo & { id: Option.Some<string> }
export type AnonymousTodo = Todo & { id: Option.None<string> }
export const JsonifiableTodo = Todo.pipe(Jsonifiable(S.Struct({ export const JsonifiableTodo = Todo.pipe(Jsonifiable(S.Struct({
...Todo.fields, ...Todo.fields,

View File

@@ -1,5 +1,5 @@
import { Todo } from "@todo-tests/common/data" import { Todo, type IdentifiedTodo } from "@todo-tests/common/data"
import { Array, Context, Data, Effect, Equal, Layer, Option, Order, Ref, SubscriptionRef } from "effect" import { Array, Context, Data, Effect, Equal, Layer, Option, Order, Ref, SubscriptionRef, flow } from "effect"
import crypto from "node:crypto" import crypto from "node:crypto"
@@ -7,7 +7,7 @@ export class TodoRepository extends Context.Tag("TodoRepository")<TodoRepository
export module TodoRepository { export module TodoRepository {
export const Live = Layer.effect(TodoRepository, export const Live = Layer.effect(TodoRepository,
SubscriptionRef.make(Array.empty<Todo & { id: Option.Some<string> }>()).pipe( SubscriptionRef.make(Array.empty<IdentifiedTodo>()).pipe(
Effect.map(ref => new TodoRepositoryService(ref)) Effect.map(ref => new TodoRepositoryService(ref))
) )
) )
@@ -17,7 +17,7 @@ export module TodoRepository {
export class TodoRepositoryService { export class TodoRepositoryService {
constructor( constructor(
readonly todos: SubscriptionRef.SubscriptionRef<(Todo & { id: Option.Some<string> })[]> readonly todos: SubscriptionRef.SubscriptionRef<IdentifiedTodo[]>
) {} ) {}
@@ -41,10 +41,15 @@ export class TodoRepositoryService {
const id: string = crypto.randomUUID() const id: string = crypto.randomUUID()
yield* Ref.update(this.todos, Array.append(new Todo({ yield* Ref.update(this.todos, flow(
Array.append(new Todo({
...todo, ...todo,
id: Option.some(id), id: Option.some(id),
}, { disableValidation: true }) as Todo & { id: Option.Some<string> })) }) as IdentifiedTodo),
sortTodos,
updateTodosOrder,
))
return id return id
}) })
@@ -55,9 +60,14 @@ export class TodoRepositoryService {
if (Option.isNone(todo.id)) if (Option.isNone(todo.id))
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, flow(
Array.replace(
yield* yield* this.getIndexByID(todo.id.value), yield* yield* this.getIndexByID(todo.id.value),
todo as Todo & { id: Option.Some<string> }, todo as IdentifiedTodo,
),
sortTodos,
updateTodosOrder,
)) ))
}) })
} }
@@ -67,27 +77,24 @@ export class TodoRepositoryService {
if (Option.isNone(todo.id)) if (Option.isNone(todo.id))
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, flow(
Array.remove(
yield* yield* this.getIndexByID(todo.id.value) yield* yield* this.getIndexByID(todo.id.value)
),
updateTodosOrder,
)) ))
}) })
} }
sort() {
return Ref.update(this.todos, Array.sort())
}
} }
const sortTodos = Array.sortBy<(Todo & { id: Option.Some<string> })[]>( const sortTodos = Array.sortBy<IdentifiedTodo[]>(
Order.mapInput(Order.number, todo => todo.order) Order.mapInput(Order.number, todo => todo.order)
) )
const updateTodoOrders = Array.map< const updateTodosOrder = Array.map<IdentifiedTodo[], IdentifiedTodo>((todo, order) =>
(Todo & { id: Option.Some<string> })[], new Todo({ ...todo, order }, { disableValidation: true }) as IdentifiedTodo
(Todo & { id: Option.Some<string> })[] )
>()
export class TodoHasID extends Data.TaggedError("TodoHasID")<{ todo: Todo }> {} export class TodoHasID extends Data.TaggedError("TodoHasID")<{ todo: Todo }> {}
export class TodoHasNoID extends Data.TaggedError("TodoHasNoID")<{ todo: Todo }> {} export class TodoHasNoID extends Data.TaggedError("TodoHasNoID")<{ todo: Todo }> {}
@@ -98,7 +105,7 @@ export const createDefaultTodos = Effect.gen(function*() {
yield* todos.add(new Todo({ yield* todos.add(new Todo({
id: Option.none(), id: Option.none(),
order: 1, order: 0,
content: "Sort the socks", content: "Sort the socks",
due: Option.none(), due: Option.none(),
completed: false, completed: false,
@@ -108,7 +115,7 @@ export const createDefaultTodos = Effect.gen(function*() {
yield* todos.add(new Todo({ yield* todos.add(new Todo({
id: Option.none(), id: Option.none(),
order: 2, order: 1,
content: "Sort the dog", content: "Sort the dog",
due: Option.none(), due: Option.none(),
completed: false, completed: false,

View File

@@ -11,7 +11,6 @@ export const VTodo = observer(({ todo }: VTodoProps) => {
return ( return (
<div className="flex flex-col px-6 pt-10 pb-8 bg-white ring-1 shadow-xl ring-gray-900/5 sm:mx-auto sm:max-w-lg sm:rounded-lg sm:px-10"> <div className="flex flex-col px-6 pt-10 pb-8 bg-white ring-1 shadow-xl ring-gray-900/5 sm:mx-auto sm:max-w-lg sm:rounded-lg sm:px-10">
<p className="text-xs">{todo.title}</p>
<p className="text-sm">{todo.content}</p> <p className="text-sm">{todo.content}</p>
</div> </div>
) )