Skip to content

Commit 7191fc1

Browse files
committed
improve: align remove/removeById/save
1 parent d1a6f57 commit 7191fc1

6 files changed

Lines changed: 55 additions & 29 deletions

File tree

.changeset/remove-by-id-array.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@effect-app/infra": patch
3+
---
4+
5+
`removeById` now takes `id | NonEmptyReadonlyArray<id>` instead of a variadic rest, and the extended repo's `removeById` accepts a `batch` option to chunk large deletes — consistent with `save` and `remove`.

.claude/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
"Bash(git commit -m ':*)",
55
"Bash(pnpm -r check)",
66
"Bash(pnpm lint-fix:*)",
7-
"Bash(git commit -m ' *)"
7+
"Bash(git commit -m ' *)",
8+
"Read(//home/patroza/pj/effect-app/**)"
89
]
910
}
1011
}

packages/infra/src/Model/Repository/ext.ts

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,10 @@ export const extendRepo = <
263263
request: (id: T[IdKey]) => Effect.request(_request({ id }), requestResolver),
264264
get,
265265
log: (evt: Evt) => AnyPureDSL.log(evt),
266+
/**
267+
* Enables chunked writes for large batches via `options.batch`.
268+
* Note: batching breaks transactional properties because chunks are saved independently.
269+
*/
266270
save: ((itemOrItems: T | NonEmptyReadonlyArray<T>, options?: BatchOptions) => {
267271
const items = asReadonlyArray(itemOrItems)
268272
const batchSize = getBatchSize(options?.batch)
@@ -274,23 +278,19 @@ export const extendRepo = <
274278
(batch) => repo.saveAndPublish(batch),
275279
{ discard: true }
276280
)
277-
}) as {
278-
(item: T, options?: BatchOptions): Effect.Effect<
279-
void,
280-
InvalidStateError | OptimisticConcurrencyException,
281-
RSchema | RPublish
282-
>
283-
(items: NonEmptyReadonlyArray<T>, options?: BatchOptions): Effect.Effect<
284-
void,
285-
InvalidStateError | OptimisticConcurrencyException,
286-
RSchema | RPublish
287-
>
288-
/**
289-
* Enables chunked writes for large batches.
290-
* Note: batching breaks transactional properties because chunks are saved independently.
291-
*/
292-
},
281+
}) as (
282+
itemOrItems: T | NonEmptyReadonlyArray<T>,
283+
options?: BatchOptions
284+
) => Effect.Effect<
285+
void,
286+
InvalidStateError | OptimisticConcurrencyException,
287+
RSchema | RPublish
288+
>,
293289
saveWithEvents: (events: Iterable<Evt>) => (...items: NonEmptyArray<T>) => repo.saveAndPublish(items, events),
290+
/**
291+
* Enables chunked deletes for large batches via `options.batch`.
292+
* Note: batching breaks transactional properties because chunks are removed independently.
293+
*/
294294
remove: ((itemOrItems: T | NonEmptyReadonlyArray<T>, options?: BatchOptions) => {
295295
const items = asReadonlyArray(itemOrItems)
296296
const batchSize = getBatchSize(options?.batch)
@@ -302,14 +302,29 @@ export const extendRepo = <
302302
(batch) => repo.removeAndPublish(batch),
303303
{ discard: true }
304304
)
305-
}) as {
306-
(item: T, options?: BatchOptions): Effect.Effect<void, never, RSchema | RPublish>
307-
(items: NonEmptyReadonlyArray<T>, options?: BatchOptions): Effect.Effect<void, never, RSchema | RPublish>
308-
/**
309-
* Enables chunked deletes for large batches.
310-
* Note: batching breaks transactional properties because chunks are removed independently.
311-
*/
312-
},
305+
}) as (
306+
itemOrItems: T | NonEmptyReadonlyArray<T>,
307+
options?: BatchOptions
308+
) => Effect.Effect<void, never, RSchema | RPublish>,
309+
/**
310+
* Enables chunked deletes for large batches via `options.batch`.
311+
* Note: batching breaks transactional properties because chunks are removed independently.
312+
*/
313+
removeById: ((idOrIds: T[IdKey] | NonEmptyReadonlyArray<T[IdKey]>, options?: BatchOptions) => {
314+
const ids = asReadonlyArray(idOrIds) as NonEmptyReadonlyArray<T[IdKey]>
315+
const batchSize = getBatchSize(options?.batch)
316+
if (batchSize === undefined) {
317+
return repo.removeById(ids)
318+
}
319+
return Effect.forEach(
320+
Array.chunksOf(ids, batchSize),
321+
(batch) => repo.removeById(batch),
322+
{ discard: true }
323+
)
324+
}) as (
325+
idOrIds: T[IdKey] | NonEmptyReadonlyArray<T[IdKey]>,
326+
options?: BatchOptions
327+
) => Effect.Effect<void, never, RSchema>,
313328
queryAndSavePure,
314329
saveManyWithPure,
315330
byIdAndSaveWithPure,

packages/infra/src/Model/Repository/internal/internal.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,10 @@ export function makeRepoInternal<
233233
)
234234

235235
const removeById = Effect.fn("removeById", { attributes: { itemType: name } })(
236-
function*(...ids: readonly T[IdKey][]) {
236+
function*(idOrIds: T[IdKey] | NonEmptyReadonlyArray<T[IdKey]>) {
237+
const ids = globalThis.Array.isArray(idOrIds)
238+
? idOrIds as readonly T[IdKey][]
239+
: [idOrIds as T[IdKey]]
237240
if (!Array.isReadonlyArrayNonEmpty(ids)) {
238241
return
239242
}

packages/infra/src/Model/Repository/service.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* eslint-disable @typescript-eslint/no-explicit-any */
2-
import type { Effect, Option, PubSub, S } from "effect-app"
2+
import type { Effect, NonEmptyReadonlyArray, Option, PubSub, S } from "effect-app"
33
import type { InvalidStateError, NotFoundError, OptimisticConcurrencyException } from "effect-app/client/errors"
44
import type { NonNegativeInt } from "effect-app/Schema/numbers"
55
import type { FieldValues, IsNever, ResolveFirstLevel } from "../filter/types.js"
@@ -31,7 +31,9 @@ export interface Repository<
3131
events?: Iterable<Evt>
3232
) => Effect.Effect<void, never, RSchema | RPublish>
3333

34-
readonly removeById: (...id: readonly T[IdKey][]) => Effect.Effect<void, never, RSchema>
34+
readonly removeById: (
35+
idOrIds: T[IdKey] | NonEmptyReadonlyArray<T[IdKey]>
36+
) => Effect.Effect<void, never, RSchema>
3537

3638
readonly queryRaw: <T, Out, R>(
3739
schema: S.Codec<T, Out, R>,

packages/infra/test/rawQuery.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ describe("removeByIds", () => {
409409

410410
yield* repo.saveAndPublish(items)
411411
const itemsAfterSave = yield* repo.all
412-
yield* repo.removeById(...items.slice(0, 2).map((_) => _.id))
412+
yield* repo.removeById([items[0]!.id, items[1]!.id])
413413

414414
const items2 = yield* repo.all
415415

0 commit comments

Comments
 (0)