test-rxdb
Version:
A local realtime NoSQL Database for JavaScript applications -
189 lines (174 loc) • 5.86 kB
text/typescript
import {
fillWithDefaultSettings,
getComposedPrimaryKeyOfDocumentData,
getLengthOfPrimaryKey
} from '../rx-schema-helper.ts';
import { flatCloneDocWithMeta } from '../rx-storage-helper.ts';
import type {
BulkWriteRow,
ById,
RxDocumentData,
RxJsonSchema,
RxStorageInstanceReplicationState,
RxStorageReplicationMeta,
WithDeleted
} from '../types/index.d.ts';
import {
getDefaultRevision,
createRevision,
now
} from '../plugins/utils/index.ts';
export const META_INSTANCE_SCHEMA_TITLE = 'RxReplicationProtocolMetaData';
export function getRxReplicationMetaInstanceSchema<RxDocType, CheckpointType>(
replicatedDocumentsSchema: RxJsonSchema<RxDocumentData<RxDocType>>,
encrypted: boolean
): RxJsonSchema<RxDocumentData<RxStorageReplicationMeta<RxDocType, CheckpointType>>> {
const parentPrimaryKeyLength = getLengthOfPrimaryKey(replicatedDocumentsSchema);
const baseSchema: RxJsonSchema<RxStorageReplicationMeta<RxDocType, CheckpointType>> = {
title: META_INSTANCE_SCHEMA_TITLE,
primaryKey: {
key: 'id',
fields: [
'itemId',
'isCheckpoint'
],
separator: '|'
},
type: 'object',
version: replicatedDocumentsSchema.version,
additionalProperties: false,
properties: {
id: {
type: 'string',
minLength: 1,
// add +1 for the '|' and +1 for the 'isCheckpoint' flag
maxLength: parentPrimaryKeyLength + 2
},
isCheckpoint: {
type: 'string',
enum: [
'0',
'1'
],
minLength: 1,
maxLength: 1
},
itemId: {
type: 'string',
/**
* ensure that all values of RxStorageReplicationDirection ('DOWN' has 4 chars) fit into it
* because checkpoints use the itemId field for that.
*/
maxLength: parentPrimaryKeyLength > 4 ? parentPrimaryKeyLength : 4
},
checkpointData: {
type: 'object',
additionalProperties: true
},
docData: {
type: 'object',
properties: replicatedDocumentsSchema.properties
},
isResolvedConflict: {
type: 'string'
}
},
keyCompression: replicatedDocumentsSchema.keyCompression,
required: [
'id',
'isCheckpoint',
'itemId'
]
};
if (encrypted) {
baseSchema.encrypted = ['docData'];
}
const metaInstanceSchema: RxJsonSchema<RxDocumentData<RxStorageReplicationMeta<RxDocType, CheckpointType>>> = fillWithDefaultSettings(baseSchema);
return metaInstanceSchema;
}
/**
* Returns the document states of what the fork instance
* assumes to be the latest state on the master instance.
*/
export function getAssumedMasterState<RxDocType>(
state: RxStorageInstanceReplicationState<RxDocType>,
docIds: string[]
): Promise<ById<{
docData: WithDeleted<RxDocType>;
metaDocument: RxDocumentData<RxStorageReplicationMeta<RxDocType, any>>;
}>> {
return state.input.metaInstance.findDocumentsById(
docIds.map(docId => {
const useId = getComposedPrimaryKeyOfDocumentData(
state.input.metaInstance.schema,
{
itemId: docId,
isCheckpoint: '0'
}
);
return useId;
}),
true
).then(metaDocs => {
const ret: {
[docId: string]: {
docData: RxDocumentData<RxDocType>;
metaDocument: RxDocumentData<RxStorageReplicationMeta<RxDocType, any>>;
};
} = {};
Object
.values(metaDocs)
.forEach((metaDoc) => {
ret[metaDoc.itemId] = {
docData: metaDoc.docData,
metaDocument: metaDoc
};
});
return ret;
});
}
export async function getMetaWriteRow<RxDocType>(
state: RxStorageInstanceReplicationState<RxDocType>,
newMasterDocState: WithDeleted<RxDocType>,
previous?: RxDocumentData<RxStorageReplicationMeta<RxDocType, any>>,
isResolvedConflict?: string
): Promise<BulkWriteRow<RxStorageReplicationMeta<RxDocType, any>>> {
const docId: string = (newMasterDocState as any)[state.primaryPath];
const newMeta: RxDocumentData<RxStorageReplicationMeta<RxDocType, any>> = previous ? flatCloneDocWithMeta(
previous
) : {
id: '',
isCheckpoint: '0',
itemId: docId,
docData: newMasterDocState,
_attachments: {},
_deleted: false,
_rev: getDefaultRevision(),
_meta: {
lwt: 0
}
};
newMeta.docData = newMasterDocState;
/**
* Sending isResolvedConflict with the value undefined
* will throw a schema validation error because it must be either
* not set or have a string.
*/
if (isResolvedConflict) {
newMeta.isResolvedConflict = isResolvedConflict;
}
newMeta._meta.lwt = now();
newMeta.id = getComposedPrimaryKeyOfDocumentData(
state.input.metaInstance.schema,
newMeta
);
newMeta._rev = createRevision(
await state.checkpointKey,
previous
);
const ret = {
previous,
document: newMeta
};
return ret;
}