TodoRepository work
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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<IdentifiedTodo[]>(
|
||||||
|
|
||||||
const sortTodos = Array.sortBy<(Todo & { id: Option.Some<string> })[]>(
|
|
||||||
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,
|
||||||
|
|||||||
@@ -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>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user