UNPKG

js-node-arango

Version:
480 lines 21.2 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ArangoDBProvider = exports.RevisionNotMatchingError = exports.ArangoError = void 0; const js_node_errors_1 = __importStar(require("js-node-errors")); const js_node_logger_1 = require("js-node-logger"); const arangojs_1 = require("arangojs"); const http_status_1 = __importDefault(require("http-status")); const document_query_builder_1 = require("./querybuilder/document-query-builder"); const edge_query_builder_1 = require("./querybuilder/edge-query-builder"); class ArangoError extends js_node_errors_1.default { constructor(error) { super(error.message, { status: http_status_1.default.INTERNAL_SERVER_ERROR, isPublic: false, }, error); } } exports.ArangoError = ArangoError; class RevisionNotMatchingError extends js_node_errors_1.default { constructor(id, error) { super(`conflict, _rev values do not match for resource: ${id}`, { status: http_status_1.default.PRECONDITION_FAILED, code: 'error.resource.revision-not-matching', isPublic: true, }, error); } } exports.RevisionNotMatchingError = RevisionNotMatchingError; class ArangoDBProvider { constructor(config, loggerConfig) { this.registerFunction = (name, code) => { return this.db.createFunction(name, code); }; this.config = config; this.logger = loggerConfig ? (0, js_node_logger_1.getLogger)(loggerConfig) : undefined; if (process.env.NODE_ENV === 'test') { this.shouldWaitForViewUpdate = true; } else { this.shouldWaitForViewUpdate = false; } } initializeDBConnection(username, password, dbName) { return __awaiter(this, void 0, void 0, function* () { var _a, _b; this.db = new arangojs_1.Database({ url: this.config.uri, databaseName: dbName !== null && dbName !== void 0 ? dbName : this.config.dbName, auth: { username, password }, }); try { yield this.db.exists(); (_a = this.logger) === null || _a === void 0 ? void 0 : _a.info(`Connected DB successfully on ${this.config.uri}`); } catch (err) { (_b = this.logger) === null || _b === void 0 ? void 0 : _b.error(err instanceof Error ? err.message : err); throw err; } }); } disconnectDB(cb) { var _a; this.db.close(); if (cb) { cb(null); } (_a = this.logger) === null || _a === void 0 ? void 0 : _a.info('Closed DB successfully'); } removeDB() { return __awaiter(this, arguments, void 0, function* (databaseName = this.config.dbName) { var _a; yield this.db.dropDatabase(databaseName); (_a = this.logger) === null || _a === void 0 ? void 0 : _a.info(`Dropped DB ${databaseName} successfully`); }); } addDB() { return __awaiter(this, arguments, void 0, function* (databaseName = this.config.dbName) { var _a; const newDb = yield this.db.createDatabase(databaseName); (_a = this.logger) === null || _a === void 0 ? void 0 : _a.info(`Created DB ${databaseName} successfully`); return newDb; }); } switchDB(database, username, password) { return __awaiter(this, void 0, void 0, function* () { if (database instanceof arangojs_1.Database) { this.db = database; } else { if (!username || !password) throw new Error('Please provide username and password'); return this.initializeDBConnection(username, password, database); } }); } createCollection(collectionName) { return __awaiter(this, void 0, void 0, function* () { var _a; yield this.db.createCollection(collectionName); (_a = this.logger) === null || _a === void 0 ? void 0 : _a.info(`Created the ${collectionName} collection successfully`); }); } createEdgeCollection(collectionName) { return __awaiter(this, void 0, void 0, function* () { var _a; yield this.db.createEdgeCollection(collectionName); (_a = this.logger) === null || _a === void 0 ? void 0 : _a.info(`Created the ${collectionName} edge collection successfully`); }); } createView(viewName, collectionName) { return __awaiter(this, void 0, void 0, function* () { var _a; const view = yield this.db.createView(viewName); const link = { analyzers: ['identity', 'text_en'], fields: {}, includeAllFields: true, primarySortCompression: 'lz4', storeValues: 'id', trackListPositions: false, }; const props = { links: {} }; props.links[collectionName] = link; yield view.updateProperties(props); (_a = this.logger) === null || _a === void 0 ? void 0 : _a.info(`Created the ${viewName} view successfully`); }); } cleanCollection(collectionName) { return __awaiter(this, void 0, void 0, function* () { const collection = this.db.collection(collectionName); yield collection.truncate(); }); } addToCollection(collectionName, item) { return __awaiter(this, void 0, void 0, function* () { var _a; (_a = this.logger) === null || _a === void 0 ? void 0 : _a.debug(`AddToCollection collectionName: %s, with item: %s`, collectionName, item); const collection = this.db.collection(collectionName); const doc = yield collection.save(item, { returnNew: true }); return doc; }); } updateDocumentInCollection(collectionName, id, docPatch, rev) { return __awaiter(this, void 0, void 0, function* () { var _a; (_a = this.logger) === null || _a === void 0 ? void 0 : _a.debug('Update DocumentCollection collectionName: %s, with docId: %s and docPatch: %o', collectionName, id, docPatch); const collection = this.db.collection(collectionName); try { if (rev) { return yield collection.update(id, Object.assign({ _rev: rev }, docPatch), { returnNew: true, ignoreRevs: false, keepNull: false }); } return yield collection.update(id, docPatch, { returnNew: true, keepNull: false }); } catch (error) { if (error.code === 404) { throw new js_node_errors_1.ResourceNotFoundError(id, error); } if (error.code === 412) { // eslint-disable-next-line @typescript-eslint/no-throw-literal throw new RevisionNotMatchingError(id, error); } throw error; } }); } deleteDocumentInCollection(collectionName, id) { return __awaiter(this, void 0, void 0, function* () { var _a; (_a = this.logger) === null || _a === void 0 ? void 0 : _a.debug('Delete DocumentCollection collectionName: %s, with docId: %s', collectionName, id); const collection = this.db.collection(collectionName); try { return yield collection.remove(id); } catch (error) { if (error.code === 404) { throw new js_node_errors_1.ResourceNotFoundError(id, error); } if (error.code === 412) { // eslint-disable-next-line @typescript-eslint/no-throw-literal throw new RevisionNotMatchingError(id, error); } throw error; } }); } getByIdFromCollection(collectionName, id) { return __awaiter(this, void 0, void 0, function* () { const collection = this.db.collection(collectionName); try { const doc = yield collection.document(id); return doc; } catch (error) { throw new js_node_errors_1.ResourceNotFoundError(id, error); } }); } getLinksFromViewForId(edgeCollectionViewName, linkedCollectionName, id) { return __awaiter(this, void 0, void 0, function* () { var _a; const view = this.db.view(edgeCollectionViewName); const aqlQuery = (0, arangojs_1.aql) ` FOR edge in ${view} SEARCH edge._from == ${linkedCollectionName + '/' + id} OPTIONS { waitForSync: ${this.shouldWaitForViewUpdate} } RETURN edge `; (_a = this.logger) === null || _a === void 0 ? void 0 : _a.debug(`Fetch query %s, with params: %s`, aqlQuery.query, aqlQuery.bindVars); const cursor = yield this.db.query(aqlQuery); return cursor.all(); }); } getLinksFromViewForToId(edgeCollectionViewName, linkedCollectionName, id) { return __awaiter(this, void 0, void 0, function* () { var _a; const view = this.db.view(edgeCollectionViewName); const aqlQuery = (0, arangojs_1.aql) ` FOR edge in ${view} SEARCH edge._to == ${linkedCollectionName + '/' + id} OPTIONS { waitForSync: ${this.shouldWaitForViewUpdate} } RETURN edge._from `; (_a = this.logger) === null || _a === void 0 ? void 0 : _a.debug(`Fetch query %s, with params: %s`, aqlQuery.query, aqlQuery.bindVars); const cursor = yield this.db.query(aqlQuery); return cursor.all(); }); } getOutBoundDocumentsForEntityId(edgeCollectionViewName, entityName, entityId, collectionName) { return __awaiter(this, void 0, void 0, function* () { var _a; const view = this.db.view(edgeCollectionViewName); const collection = this.db.collection(collectionName); const entityValue = entityName + '/' + entityId; const aqlQuery = (0, arangojs_1.aql) `FOR edge IN ${view} OPTIONS { waitForSync: ${this.shouldWaitForViewUpdate} } FOR doc IN ${collection} FILTER edge._from == ${entityValue} && doc._id == edge._to FILTER doc.deleted == false || doc.deleted == null RETURN doc`; (_a = this.logger) === null || _a === void 0 ? void 0 : _a.debug(`Fetch query %s, with params: %s`, aqlQuery.query, aqlQuery.bindVars); const cursor = yield this.db.query(aqlQuery); return cursor.all(); }); } /** * @deprecated Please use getDocuments method instead of getFromCollection */ getFromCollection(collectionName, sortField, sortOrder, limit, offset, // eslint-disable-next-line @typescript-eslint/no-unused-vars filter) { var _a; const collection = this.db.collection(collectionName); let aqlQuery; const filters = []; if (filter) { filters.push((0, arangojs_1.aql) `FILTER ${filter}`); } aqlQuery = (0, arangojs_1.aql) ` FOR doc IN ${collection} SORT doc.${sortField} ${sortOrder} ${arangojs_1.aql.join(filters)} LIMIT ${offset}, ${limit} RETURN doc`; (_a = this.logger) === null || _a === void 0 ? void 0 : _a.debug(`Fetch query %s, with params: %s`, aqlQuery.query, aqlQuery.bindVars); return this.db.query(aqlQuery); } getByFieldNameFromCollection(collectionName, fieldName, value) { var _a; const collection = this.db.collection(collectionName); const aqlQuery = (0, arangojs_1.aql) ` FOR doc IN ${collection} FILTER doc.${fieldName} == ${value} RETURN doc `; (_a = this.logger) === null || _a === void 0 ? void 0 : _a.debug(`Fetch query %s, with params: %s`, aqlQuery.query, aqlQuery.bindVars); return this.db.query(aqlQuery); } executeRawQuery(aqlQuery, options) { return __awaiter(this, void 0, void 0, function* () { var _a; (_a = this.logger) === null || _a === void 0 ? void 0 : _a.debug('Query %s, with params: %O', aqlQuery.query, aqlQuery.bindVars); const cur = yield this.db.query(aqlQuery, options); return cur.all(); }); } /** * Just a shortcut method for returning the first result from the query result set * ```js * const resultSet = await this.executeRawQuery<T>(query, options); * return resultSet[0]; * ``` */ executeRawQueryReturnFirst(aqlQuery, options) { return __awaiter(this, void 0, void 0, function* () { const resultSet = yield this.executeRawQuery(aqlQuery, options); return resultSet[0]; }); } addToCollectionWithRelatedDocument(inputArgs) { return __awaiter(this, void 0, void 0, function* () { var _a; const aqlQuery = { query: `LET rootDoc = FIRST(INSERT @rootDoc INTO @@rootDocCollectionName RETURN NEW) LET related = FIRST(INSERT @relatedDoc INTO @@relatedCollectionName RETURN NEW) INSERT MERGE({ _from: rootDoc._id, _to: related._id, _key: UUID() }, @additionalLinkData) into @@edgeCollectionName RETURN { rootDoc, related }`, bindVars: { '@rootDocCollectionName': inputArgs.rootDocCollectionName, '@relatedCollectionName': inputArgs.relatedCollectionName, '@edgeCollectionName': inputArgs.edgeCollectionName, rootDoc: inputArgs.rootDoc, relatedDoc: inputArgs.relatedDoc, additionalLinkData: (_a = inputArgs.additionalLinkData) !== null && _a !== void 0 ? _a : {}, }, }; return this.executeRawQueryReturnFirst(aqlQuery); }); } addRelatedDocument(inputArgs) { return __awaiter(this, void 0, void 0, function* () { var _a; const aqlQuery = { query: `LET related = FIRST(INSERT @relatedDoc INTO @@relatedCollectionName RETURN NEW) INSERT MERGE({ _from: @fromId, _to: related._id, _key: UUID() }, @additionalLinkData) into @@edgeCollectionName RETURN related`, bindVars: { '@relatedCollectionName': inputArgs.relatedCollectionName, '@edgeCollectionName': inputArgs.edgeCollectionName, fromId: `${inputArgs.rootDocCollectionName}/${inputArgs.rootDocId}`, relatedDoc: inputArgs.relatedDoc, additionalLinkData: (_a = inputArgs.additionalLinkData) !== null && _a !== void 0 ? _a : {}, }, }; return this.executeRawQueryReturnFirst(aqlQuery); }); } /** * Basic query with options. * * @example * ```js * // This query will return all documents matches the given example * const results = await this.db.getDocuments('manifest', { * filterBy: { * filter: { * gitRepoInfo: { * owner: 'Tospaa', * }, * }, * }, * }); * return results; * * // This query will return the first document matches the given example * const results = await this.db.getDocuments('git_account', { * limitBy: { * offset: 0, * limit: 1, * }, * sortBy: { * field: 'dateTs', * order: 'DESC', * }, * filterBy: { * filter: { * cognitoUsername: '26fcf457-e31a-4219-91e0-878ed039024c', * status: 'active', * }, * }, * }); * return results[0]; * * // This query will return all the documents in the given collection * const results = await this.db.getDocuments('git_repo'); * return results; * ``` * @param collectionName The name of the collection * @param options Arango Query Options * @returns All results matching the given criteria */ getDocuments(options) { return __awaiter(this, void 0, void 0, function* () { var _a; if (options.withCount) { (_a = this.logger) === null || _a === void 0 ? void 0 : _a.warn('Consider using getDocumentsWithCount method if you need the total count for type safety'); } const builder = new document_query_builder_1.ArangoDocumentQueryBuilder(options); return this.executeRawQuery(builder.prepareQuery()); }); } getDocumentsWithCount(options) { return __awaiter(this, void 0, void 0, function* () { options.withCount = true; const builder = new document_query_builder_1.ArangoDocumentQueryBuilder(options); return this.executeRawQueryReturnFirst(builder.prepareQuery()); }); } getDocumentWithRelatedDocuments(collectionName, rootDocId, options) { return __awaiter(this, void 0, void 0, function* () { var _a; if (options.withCount) { (_a = this.logger) === null || _a === void 0 ? void 0 : _a.warn('Consider using getDocumentWithRelatedDocumentsWithCount method if you need the total count for type safety'); } const rootDoc = 'rootDoc'; const builder = new document_query_builder_1.ArangoDocumentQueryBuilder({ documentCollection: collectionName, filterBy: { filter: { _key: rootDocId } }, }) .setDocSelector(rootDoc) .addAdditionalQuery('related', new edge_query_builder_1.ArangoEdgeQueryBuilder(options).setRootDocSelector(rootDoc)); return this.executeRawQueryReturnFirst(builder.prepareQuery()); }); } getDocumentWithRelatedDocumentsWithCount(collectionName, rootDocId, options) { return __awaiter(this, void 0, void 0, function* () { options.withCount = true; const rootDoc = 'rootDoc'; const builder = new document_query_builder_1.ArangoDocumentQueryBuilder({ documentCollection: collectionName, filterBy: { filter: { _key: rootDocId } }, }) .setDocSelector(rootDoc) .addAdditionalQuery('related', new edge_query_builder_1.ArangoEdgeQueryBuilder(options).setRootDocSelector(rootDoc)); return this.executeRawQueryReturnFirst(builder.prepareQuery()); }); } } exports.ArangoDBProvider = ArangoDBProvider; exports.default = ArangoDBProvider; //# sourceMappingURL=index.js.map