54 lines
2.4 KiB
TypeScript
54 lines
2.4 KiB
TypeScript
export interface DirtyState {
|
|
currentMainRevision: number;
|
|
committedMainRevision: number;
|
|
dirty: boolean;
|
|
}
|
|
|
|
export type DirtyStateResult =
|
|
| { ok: true; state: DirtyState }
|
|
| { ok: false; state: DirtyState; errorCode: "DIRTY_REVISION_INVALID" | "DIRTY_REVISION_STALE" | "DIRTY_SAVE_REVISION_MISMATCH" };
|
|
|
|
function validRevision(revision: number): boolean {
|
|
return Number.isSafeInteger(revision) && revision >= 0;
|
|
}
|
|
|
|
export function createDirtyState(revision = 0): DirtyState {
|
|
if (!validRevision(revision)) throw new Error("DIRTY_REVISION_INVALID");
|
|
return { currentMainRevision: revision, committedMainRevision: revision, dirty: false };
|
|
}
|
|
|
|
export function recoverDirtyState(currentMainRevision: number, committedMainRevision: number): DirtyState {
|
|
if (!validRevision(currentMainRevision) || !validRevision(committedMainRevision) || currentMainRevision < committedMainRevision) {
|
|
throw new Error("DIRTY_REVISION_INVALID");
|
|
}
|
|
return { currentMainRevision, committedMainRevision, dirty: currentMainRevision !== committedMainRevision };
|
|
}
|
|
|
|
export function acceptMainTransaction(state: DirtyState, revision: number): DirtyStateResult {
|
|
if (!validRevision(revision)) return { ok: false, state, errorCode: "DIRTY_REVISION_INVALID" };
|
|
if (revision <= state.currentMainRevision) return { ok: false, state, errorCode: "DIRTY_REVISION_STALE" };
|
|
return {
|
|
ok: true,
|
|
state: { ...state, currentMainRevision: revision, dirty: revision !== state.committedMainRevision },
|
|
};
|
|
}
|
|
|
|
export function acceptMainSave(state: DirtyState, revision: number): DirtyStateResult {
|
|
if (!validRevision(revision)) return { ok: false, state, errorCode: "DIRTY_REVISION_INVALID" };
|
|
if (revision !== state.currentMainRevision) return { ok: false, state, errorCode: "DIRTY_SAVE_REVISION_MISMATCH" };
|
|
return { ok: true, state: { currentMainRevision: revision, committedMainRevision: revision, dirty: false } };
|
|
}
|
|
|
|
export function acceptHistoryTransaction(state: DirtyState, revision: number, matchesCommittedContent: boolean): DirtyStateResult {
|
|
if (!validRevision(revision)) return { ok: false, state, errorCode: "DIRTY_REVISION_INVALID" };
|
|
if (revision <= state.currentMainRevision) return { ok: false, state, errorCode: "DIRTY_REVISION_STALE" };
|
|
return {
|
|
ok: true,
|
|
state: {
|
|
currentMainRevision: revision,
|
|
committedMainRevision: matchesCommittedContent ? revision : state.committedMainRevision,
|
|
dirty: !matchesCommittedContent,
|
|
},
|
|
};
|
|
}
|