test-rxdb
Version:
A local realtime NoSQL Database for JavaScript applications -
105 lines (98 loc) • 3.44 kB
text/typescript
import type {
RxConflictHandler,
RxConflictHandlerInput,
RxConflictHandlerOutput,
RxDocumentData,
RxStorageInstanceReplicationState
} from '../types/index.d.ts';
import {
getDefaultRevision,
createRevision,
now,
flatClone,
deepEqual
} from '../plugins/utils/index.ts';
import { stripAttachmentsDataFromDocument } from '../rx-storage-helper.ts';
export const defaultConflictHandler: RxConflictHandler<any> = function (
i: RxConflictHandlerInput<any>,
_context: string
): Promise<RxConflictHandlerOutput<any>> {
const newDocumentState = stripAttachmentsDataFromDocument(i.newDocumentState);
const realMasterState = stripAttachmentsDataFromDocument(i.realMasterState);
/**
* If the documents are deep equal,
* we have no conflict.
* On your custom conflict handler you might only
* check some properties, like the updatedAt time,
* for better performance, because deepEqual is expensive.
*/
if (deepEqual(
newDocumentState,
realMasterState
)) {
return Promise.resolve({
isEqual: true
});
}
/**
* The default conflict handler will always
* drop the fork state and use the master state instead.
*/
return Promise.resolve({
isEqual: false,
documentData: i.realMasterState
});
};
/**
* Resolves a conflict error or determines that the given document states are equal.
* Returns the resolved document that must be written to the fork.
* Then the new document state can be pushed upstream.
* If document is not in conflict, returns undefined.
* If error is non-409, it throws an error.
* Conflicts are only solved in the upstream, never in the downstream.
*/
export async function resolveConflictError<RxDocType>(
state: RxStorageInstanceReplicationState<RxDocType>,
input: RxConflictHandlerInput<RxDocType>,
forkState: RxDocumentData<RxDocType>
): Promise<{
resolvedDoc: RxDocumentData<RxDocType>;
output: RxConflictHandlerOutput<RxDocType>;
} | undefined> {
const conflictHandler: RxConflictHandler<RxDocType> = state.input.conflictHandler;
const conflictHandlerOutput = await conflictHandler(input, 'replication-resolve-conflict');
if (conflictHandlerOutput.isEqual) {
/**
* Documents are equal,
* so this is not a conflict -> do nothing.
*/
return undefined;
} else {
/**
* We have a resolved conflict,
* use the resolved document data.
*/
const resolvedDoc: RxDocumentData<RxDocType> = Object.assign(
{},
conflictHandlerOutput.documentData,
{
/**
* Because the resolved conflict is written to the fork,
* we have to keep/update the forks _meta data, not the masters.
*/
_meta: flatClone(forkState._meta),
_rev: getDefaultRevision(),
_attachments: flatClone(forkState._attachments)
}
) as any;
resolvedDoc._meta.lwt = now();
resolvedDoc._rev = createRevision(
await state.checkpointKey,
forkState
);
return {
resolvedDoc,
output: conflictHandlerOutput
};
}
}