From e88a6f7b1c1a79005d2ff3cc7a4e0cd8e1d07dd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Mon, 8 Jul 2024 21:38:44 +0200 Subject: [PATCH] TodoRepository work --- packages/common/src/data/Todo.class.ts | 4 ++ packages/server/src/TodoRepository.ts | 57 +++++++++++++++----------- packages/webui/src/todo/VTodo.tsx | 1 - 3 files changed, 36 insertions(+), 26 deletions(-) diff --git a/packages/common/src/data/Todo.class.ts b/packages/common/src/data/Todo.class.ts index 8f4ec86..3863ec8 100644 --- a/packages/common/src/data/Todo.class.ts +++ b/packages/common/src/data/Todo.class.ts @@ -1,6 +1,7 @@ import { Schema as S } from "@effect/schema" import { Jsonifiable, Kind, Tag } from "@thilawyn/thilalib/effect/schema" import { Class } from "@thilawyn/thilalib/effect/schema/class" +import type { Option } from "effect" import type { Identifiable } from "../traits" @@ -22,6 +23,9 @@ export class Todo implements Identifiable<"Todo", string> {} +export type IdentifiedTodo = Todo & { id: Option.Some } +export type AnonymousTodo = Todo & { id: Option.None } + export const JsonifiableTodo = Todo.pipe(Jsonifiable(S.Struct({ ...Todo.fields, diff --git a/packages/server/src/TodoRepository.ts b/packages/server/src/TodoRepository.ts index 2f65e25..d9eeeb0 100644 --- a/packages/server/src/TodoRepository.ts +++ b/packages/server/src/TodoRepository.ts @@ -1,5 +1,5 @@ -import { Todo } from "@todo-tests/common/data" -import { Array, Context, Data, Effect, Equal, Layer, Option, Order, Ref, SubscriptionRef } from "effect" +import { Todo, type IdentifiedTodo } from "@todo-tests/common/data" +import { Array, Context, Data, Effect, Equal, Layer, Option, Order, Ref, SubscriptionRef, flow } from "effect" import crypto from "node:crypto" @@ -7,7 +7,7 @@ export class TodoRepository extends Context.Tag("TodoRepository") }>()).pipe( + SubscriptionRef.make(Array.empty()).pipe( Effect.map(ref => new TodoRepositoryService(ref)) ) ) @@ -17,7 +17,7 @@ export module TodoRepository { export class TodoRepositoryService { constructor( - readonly todos: SubscriptionRef.SubscriptionRef<(Todo & { id: Option.Some })[]> + readonly todos: SubscriptionRef.SubscriptionRef ) {} @@ -41,10 +41,15 @@ export class TodoRepositoryService { const id: string = crypto.randomUUID() - yield* Ref.update(this.todos, Array.append(new Todo({ - ...todo, - id: Option.some(id), - }, { disableValidation: true }) as Todo & { id: Option.Some })) + yield* Ref.update(this.todos, flow( + Array.append(new Todo({ + ...todo, + id: Option.some(id), + }) as IdentifiedTodo), + + sortTodos, + updateTodosOrder, + )) return id }) @@ -55,9 +60,14 @@ export class TodoRepositoryService { if (Option.isNone(todo.id)) return yield* Effect.fail(new TodoHasNoID({ todo })) - yield* Ref.update(this.todos, Array.replace( - yield* yield* this.getIndexByID(todo.id.value), - todo as Todo & { id: Option.Some }, + yield* Ref.update(this.todos, flow( + Array.replace( + yield* yield* this.getIndexByID(todo.id.value), + todo as IdentifiedTodo, + ), + + sortTodos, + updateTodosOrder, )) }) } @@ -67,27 +77,24 @@ export class TodoRepositoryService { if (Option.isNone(todo.id)) return yield* Effect.fail(new TodoHasNoID({ todo })) - yield* Ref.update(this.todos, Array.remove( - yield* yield* this.getIndexByID(todo.id.value) + yield* Ref.update(this.todos, flow( + Array.remove( + yield* yield* this.getIndexByID(todo.id.value) + ), + updateTodosOrder, )) }) } - - sort() { - return Ref.update(this.todos, Array.sort()) - } - } -const sortTodos = Array.sortBy<(Todo & { id: Option.Some })[]>( +const sortTodos = Array.sortBy( Order.mapInput(Order.number, todo => todo.order) ) -const updateTodoOrders = Array.map< - (Todo & { id: Option.Some })[], - (Todo & { id: Option.Some })[] ->() +const updateTodosOrder = Array.map((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 }> {} @@ -98,7 +105,7 @@ export const createDefaultTodos = Effect.gen(function*() { yield* todos.add(new Todo({ id: Option.none(), - order: 1, + order: 0, content: "Sort the socks", due: Option.none(), completed: false, @@ -108,7 +115,7 @@ export const createDefaultTodos = Effect.gen(function*() { yield* todos.add(new Todo({ id: Option.none(), - order: 2, + order: 1, content: "Sort the dog", due: Option.none(), completed: false, diff --git a/packages/webui/src/todo/VTodo.tsx b/packages/webui/src/todo/VTodo.tsx index 4837945..f88c8fc 100644 --- a/packages/webui/src/todo/VTodo.tsx +++ b/packages/webui/src/todo/VTodo.tsx @@ -11,7 +11,6 @@ export const VTodo = observer(({ todo }: VTodoProps) => { return (
-

{todo.title}

{todo.content}

)