UNPKG

rxdb

Version:

A local-first realtime NoSQL Database for JavaScript applications - https://rxdb.info/

190 lines (186 loc) 6.37 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.WAL_FILE_NAME = exports.DRIVE_MAX_BULK_SIZE = void 0; exports.fetchConflicts = fetchConflicts; exports.handleUpstreamBatch = handleUpstreamBatch; exports.processWalFile = processWalFile; exports.readWalContent = readWalContent; exports.writeToWal = writeToWal; var _rxError = require("../../rx-error.js"); var _index = require("../utils/index.js"); var _documentHandling = require("./document-handling.js"); var _microsoftOnedriveHelper = require("./microsoft-onedrive-helper.js"); var WAL_FILE_NAME = exports.WAL_FILE_NAME = 'rxdb-wal.json'; // Batch insert limit in Graph api is often not fully restricted for files unless using batch endpoints, // a reasonable size is 100-250 to avoid timeout. var DRIVE_MAX_BULK_SIZE = exports.DRIVE_MAX_BULK_SIZE = 250; async function fetchConflicts(oneDriveState, init, primaryPath, writeRows) { if (writeRows.length > DRIVE_MAX_BULK_SIZE) { throw (0, _rxError.newRxError)('ODR18', { args: { DRIVE_MAX_BULK_SIZE } }); } var ids = writeRows.map(row => row.newDocumentState[primaryPath]); var filesMeta = await (0, _documentHandling.getDocumentFiles)(oneDriveState, init, ids); var fileIdByDocId = new Map(); var fileIds = filesMeta.files.map(f => { var fileId = (0, _index.ensureNotFalsy)(f.id); var docId = f.name.split('.')[0]; fileIdByDocId.set(docId, fileId); return fileId; }); var contentsByFileId = await (0, _documentHandling.fetchDocumentContents)(oneDriveState, fileIds); var conflicts = []; var nonConflicts = []; writeRows.forEach(row => { var docId = row.newDocumentState[primaryPath]; var fileContent; var fileId = fileIdByDocId.get(docId); if (fileId) { fileContent = contentsByFileId.byId[fileId]; } if (row.assumedMasterState) { if (!(0, _index.deepEqual)(row.assumedMasterState, fileContent)) { conflicts.push((0, _index.ensureNotFalsy)(fileContent)); } else { nonConflicts.push(row); } } else if (fileContent) { conflicts.push(fileContent); } else { nonConflicts.push(row); } }); if (nonConflicts.length + conflicts.length !== writeRows.length) { throw (0, _rxError.newRxError)('SNH', { pushRows: writeRows, args: { nonConflicts, conflicts, contentsByFileId: contentsByFileId.byId } }); } return { conflicts, nonConflicts }; } async function writeToWal(oneDriveState, init, writeRows) { var walFileId = init.walFile.fileId; var baseUrl = (0, _microsoftOnedriveHelper.getDriveBaseUrl)(oneDriveState); var metaUrl = baseUrl + "/items/" + encodeURIComponent(walFileId) + "?$select=id,size,eTag"; var metaRes = await fetch(metaUrl, { method: "GET", headers: { Authorization: "Bearer " + oneDriveState.authToken } }); if (!metaRes.ok) { throw await (0, _rxError.newRxFetchError)(metaRes); } var meta = await metaRes.json(); var sizeNum = meta.size || 0; if (writeRows && sizeNum > 0) { throw (0, _rxError.newRxError)("ODR19", { args: { sizeNum, walFileId, meta, writeRows: writeRows?.length } }); } var etag = (0, _index.ensureNotFalsy)(meta.eTag, 'etag missing'); var writeResult = await (0, _microsoftOnedriveHelper.fillFileIfEtagMatches)(oneDriveState, walFileId, etag, writeRows); if (writeResult.status !== 200 && writeResult.status !== 201) { throw (0, _rxError.newRxError)("ODR19", { args: { walFileId, meta, writeRows: writeRows?.length } }); } } async function readWalContent(oneDriveState, init) { var walFileId = init.walFile.fileId; var baseUrl = (0, _microsoftOnedriveHelper.getDriveBaseUrl)(oneDriveState); var contentUrl = baseUrl + "/items/" + encodeURIComponent(walFileId) + "/content"; var res = await fetch(contentUrl, { method: "GET", headers: { Authorization: "Bearer " + oneDriveState.authToken } }); if (!res.ok) { throw await (0, _rxError.newRxFetchError)(res); } var etag = res.headers.get("etag") || res.headers.get("ETag"); if (!etag) { var metaRes = await fetch(baseUrl + "/items/" + encodeURIComponent(walFileId) + "?$select=eTag", { headers: { Authorization: "Bearer " + oneDriveState.authToken } }); var meta = await metaRes.json(); etag = meta.eTag; } var text = await res.text(); if (!text || !text.trim()) { return { etag: (0, _index.ensureNotFalsy)(etag), rows: undefined }; } return { etag: (0, _index.ensureNotFalsy)(etag), rows: JSON.parse(text) }; } /** * Here we read the WAL file content * and sort the content into the actual * document files. * Notice that when the JavaScript process * exists at any point here, we need to have * a recoverable state on the next run. So this * must be idempotent. */ async function processWalFile(oneDriveState, init, primaryPath) { var content = await readWalContent(oneDriveState, init); if (!content.rows) { return; } var docIds = content.rows.map(row => row.newDocumentState[primaryPath]); var docFiles = await (0, _documentHandling.getDocumentFiles)(oneDriveState, init, docIds); var fileIdByDocId = {}; docFiles.files.forEach(file => { var docId = file.name.split('.')[0]; fileIdByDocId[docId] = file.id; }); var toInsert = []; var toUpdate = []; content.rows.filter(row => { var docId = row.newDocumentState[primaryPath]; var fileExists = fileIdByDocId[docId]; if (!fileExists) { toInsert.push(row.newDocumentState); } else { toUpdate.push(row.newDocumentState); } }); await Promise.all([(0, _documentHandling.insertDocumentFiles)(oneDriveState, init, primaryPath, toInsert), (0, _documentHandling.updateDocumentFiles)(oneDriveState, primaryPath, toUpdate, fileIdByDocId)]); // overwrite wal with emptyness await writeToWal(oneDriveState, init, undefined); } async function handleUpstreamBatch(oneDriveState, init, primaryPath, writeRows) { var conflictResult = await fetchConflicts(oneDriveState, init, primaryPath, writeRows); await writeToWal(oneDriveState, init, conflictResult.nonConflicts); return conflictResult.conflicts; } //# sourceMappingURL=upstream.js.map