UNPKG

@configurator/ravendb

Version:
203 lines 9.37 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DatabaseSmuggler = void 0; const StringUtil_1 = require("../../Utility/StringUtil"); const DatabaseSmugglerImportOptions_1 = require("./DatabaseSmugglerImportOptions"); const Exceptions_1 = require("../../Exceptions"); const HttpUtil_1 = require("../../Utility/HttpUtil"); const fs = require("fs"); const StreamUtil = require("../../Utility/StreamUtil"); const LengthUnawareFormData_1 = require("../../Utility/LengthUnawareFormData"); const path = require("path"); const BackupUtils_1 = require("./BackupUtils"); const OperationCompletionAwaiter_1 = require("../Operations/OperationCompletionAwaiter"); const GetNextOperationIdCommand_1 = require("../Commands/GetNextOperationIdCommand"); const RavenCommand_1 = require("../../Http/RavenCommand"); class DatabaseSmuggler { constructor(store, databaseName) { this._store = store; this._databaseName = databaseName ?? store.database; if (this._databaseName) { this._requestExecutor = store.getRequestExecutor(this._databaseName); } else { this._requestExecutor = null; } } forDatabase(databaseName) { if (StringUtil_1.StringUtil.equalsIgnoreCase(databaseName, this._databaseName)) { return this; } return new DatabaseSmuggler(this._store, databaseName); } async export(options, toFileOrToDatabase) { if (toFileOrToDatabase instanceof DatabaseSmuggler) { const importOptions = new DatabaseSmugglerImportOptions_1.DatabaseSmugglerImportOptions(options); return await this._export(options, async (response) => { const importOperation = await toFileOrToDatabase.import(importOptions, response); await importOperation.waitForCompletion(); }); } else { const directory = path.dirname(path.resolve(toFileOrToDatabase)); if (!fs.existsSync(directory)) { fs.mkdirSync(directory, { recursive: true }); } return await this._export(options, async (response) => { const fileStream = fs.createWriteStream(toFileOrToDatabase); await StreamUtil.pipelineAsync(response, fileStream); }); } } async _export(options, handleStreamResponse) { if (!options) { (0, Exceptions_1.throwError)("InvalidArgumentException", "Options cannot be null"); } if (!this._requestExecutor) { (0, Exceptions_1.throwError)("InvalidOperationException", "Cannot use smuggler without a database defined, did you forget to call 'forDatabase'?"); } const getOperationIdCommand = new GetNextOperationIdCommand_1.GetNextOperationIdCommand(); await this._requestExecutor.execute(getOperationIdCommand); const operationId = getOperationIdCommand.result; const command = new ExportCommand(this._requestExecutor.conventions, options, handleStreamResponse, operationId, getOperationIdCommand.nodeTag); await this._requestExecutor.execute(command); return new OperationCompletionAwaiter_1.OperationCompletionAwaiter(this._requestExecutor, this._requestExecutor.conventions, operationId, getOperationIdCommand.nodeTag); } async importIncremental(options, fromDirectory) { const files = fs.readdirSync(fromDirectory) .filter(x => BackupUtils_1.BackupUtils.BACKUP_FILE_SUFFIXES.includes("." + path.extname(x))) .sort(BackupUtils_1.BackupUtils.comparator); if (!files.length) { return; } const oldOperateOnTypes = DatabaseSmuggler.configureOptionsFromIncrementalImport(options); for (let i = 0; i < files.length - 1; i++) { const filePath = files[i]; await this.import(options, path.resolve(filePath)); } options.operateOnTypes = oldOperateOnTypes; const lastFile = files.slice(-1).pop(); await this.import(options, path.resolve(lastFile)); } static configureOptionsFromIncrementalImport(options) { options.operateOnTypes.push("Tombstones"); options.operateOnTypes.push("CompareExchangeTombstones"); const oldOperateOnTypes = [...options.operateOnTypes]; options.operateOnTypes = options.operateOnTypes.filter(x => x !== "Indexes" && x !== "Subscriptions"); return oldOperateOnTypes; } async import(options, fileOrStream) { if (typeof fileOrStream === "string") { let countOfFileParts = 0; let result; let fromFile = fileOrStream; do { const fos = fs.createReadStream(fromFile); result = await this._import(options, fos); countOfFileParts++; fromFile = StringUtil_1.StringUtil.format("{0}.part{1}", fromFile, countOfFileParts); } while (fs.existsSync(fromFile)); return result; } else { return await this._import(options, fileOrStream); } } async _import(options, stream) { if (!options) { (0, Exceptions_1.throwError)("InvalidArgumentException", "Options cannot be null"); } if (!stream) { (0, Exceptions_1.throwError)("InvalidArgumentException", "Stream cannot be null"); } if (!this._requestExecutor) { (0, Exceptions_1.throwError)("InvalidOperationException", "Cannot use smuggler without a database defined, did you forget to call 'forDatabase'?"); } const getOperationIdCommand = new GetNextOperationIdCommand_1.GetNextOperationIdCommand(); await this._requestExecutor.execute(getOperationIdCommand); const operationId = getOperationIdCommand.result; const command = new ImportCommand(this._requestExecutor.conventions, options, stream, operationId, getOperationIdCommand.nodeTag); await this._requestExecutor.execute(command); return new OperationCompletionAwaiter_1.OperationCompletionAwaiter(this._requestExecutor, this._requestExecutor.conventions, operationId, getOperationIdCommand.nodeTag); } } exports.DatabaseSmuggler = DatabaseSmuggler; class ExportCommand extends RavenCommand_1.RavenCommand { constructor(conventions, options, handleStreamResponse, operationId, nodeTag) { super(); if (!conventions) { (0, Exceptions_1.throwError)("InvalidArgumentException", "Conventions cannot be null"); } if (!options) { (0, Exceptions_1.throwError)("InvalidArgumentException", "Options cannot be null"); } if (!handleStreamResponse) { (0, Exceptions_1.throwError)("InvalidArgumentException", "HandleStreamResponse cannot be null"); } this._handleStreamResponse = handleStreamResponse; const { operateOnTypes, ...restOptions } = options; this._options = conventions.objectMapper.toObjectLiteral({ operateOnTypes: operateOnTypes.join(","), ...restOptions }); this._operationId = operationId; this._selectedNodeTag = nodeTag; } get isReadRequest() { return false; } createRequest(node) { const uri = node.url + "/databases/" + node.database + "/smuggler/export?operationId=" + this._operationId; const body = this._serializer.serialize(this._options); const headers = HttpUtil_1.HeadersBuilder.create() .typeAppJson().build(); return { method: "POST", uri, body, headers }; } async processResponse(cache, response, bodyStream, url) { await this._handleStreamResponse(bodyStream); return "Automatic"; } } class ImportCommand extends RavenCommand_1.RavenCommand { get isReadRequest() { return false; } constructor(conventions, options, stream, operationId, nodeTag) { super(); this._responseType = "Empty"; if (!stream) { (0, Exceptions_1.throwError)("InvalidArgumentException", "Stream cannot be null"); } if (!conventions) { (0, Exceptions_1.throwError)("InvalidArgumentException", "Conventions cannot be null"); } if (!options) { (0, Exceptions_1.throwError)("InvalidArgumentException", "Options cannot be null"); } this._stream = stream; const { operateOnTypes, ...restOptions } = options; this._options = conventions.objectMapper.toObjectLiteral({ operateOnTypes: operateOnTypes.join(","), ...restOptions }); this._operationId = operationId; this._selectedNodeTag = nodeTag; } createRequest(node) { const uri = node.url + "/databases/" + node.database + "/smuggler/import?operationId=" + this._operationId; const multipart = new LengthUnawareFormData_1.LengthUnawareFormData(); multipart.append("importOptions", this._serializer.serialize(this._options)); multipart.append("file", this._stream, { filename: "name" }); return { method: "POST", uri, body: multipart, }; } } //# sourceMappingURL=DatabaseSmuggler.js.map