refactor: 프론트 템플릿 리펙토링
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
import type {
|
||||
BrowserDataResult,
|
||||
IndexedDbRepositoryPort,
|
||||
} from "../../../../src/application/ports/browser-file-storage/index.ts";
|
||||
|
||||
export type LocalDraft = Readonly<{
|
||||
draftId: string;
|
||||
title: string;
|
||||
body: string;
|
||||
}>;
|
||||
|
||||
export type SaveLocalDraftCommand = Readonly<{
|
||||
draft: LocalDraft;
|
||||
expectedRevision: number | null;
|
||||
idempotencyKey: string;
|
||||
}>;
|
||||
|
||||
export type RemoveLocalDraftCommand = Readonly<{
|
||||
draftId: string;
|
||||
expectedRevision: number;
|
||||
idempotencyKey: string;
|
||||
}>;
|
||||
|
||||
export type LocalDraftRecord = Readonly<{
|
||||
draft: LocalDraft;
|
||||
revision: number;
|
||||
}>;
|
||||
|
||||
export interface LocalDraftStore {
|
||||
save(
|
||||
command: SaveLocalDraftCommand,
|
||||
signal?: AbortSignal,
|
||||
): Promise<BrowserDataResult<Readonly<{ revision: number }>>>;
|
||||
find(
|
||||
draftId: string,
|
||||
signal?: AbortSignal,
|
||||
): Promise<BrowserDataResult<LocalDraftRecord | null>>;
|
||||
remove(
|
||||
command: RemoveLocalDraftCommand,
|
||||
signal?: AbortSignal,
|
||||
): Promise<BrowserDataResult<void>>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Feature-owned binding over the technology-neutral IndexedDB application port.
|
||||
*
|
||||
* The feature knows its domain type and optimistic concurrency inputs. It does
|
||||
* not know database names, stores, transactions, native IDB objects, codecs,
|
||||
* migrations, quota handling or connection lifecycle.
|
||||
*/
|
||||
export function createLocalDraftStore(
|
||||
repository: IndexedDbRepositoryPort<LocalDraft, never>,
|
||||
): LocalDraftStore {
|
||||
const store: LocalDraftStore = {
|
||||
async save(command, signal) {
|
||||
const result = await repository.compareAndSwap({
|
||||
key: command.draft.draftId,
|
||||
value: command.draft,
|
||||
expectedRevision: command.expectedRevision,
|
||||
idempotencyKey: command.idempotencyKey,
|
||||
signal,
|
||||
});
|
||||
if (!result.ok) return result;
|
||||
return Object.freeze({
|
||||
ok: true as const,
|
||||
value: Object.freeze({ revision: result.value.revision }),
|
||||
});
|
||||
},
|
||||
|
||||
async find(draftId, signal) {
|
||||
const result = await repository.read(draftId, signal);
|
||||
if (!result.ok) return result;
|
||||
return Object.freeze({
|
||||
ok: true as const,
|
||||
value:
|
||||
result.value === null
|
||||
? null
|
||||
: Object.freeze({
|
||||
draft: result.value.value,
|
||||
revision: result.value.revision,
|
||||
}),
|
||||
});
|
||||
},
|
||||
|
||||
async remove(command, signal) {
|
||||
const result = await repository.remove({
|
||||
key: command.draftId,
|
||||
expectedRevision: command.expectedRevision,
|
||||
idempotencyKey: command.idempotencyKey,
|
||||
signal,
|
||||
});
|
||||
if (!result.ok) return result;
|
||||
return Object.freeze({ ok: true as const, value: undefined });
|
||||
},
|
||||
};
|
||||
return Object.freeze(store);
|
||||
}
|
||||
Reference in New Issue
Block a user