UNPKG

triplecheck-broker

Version:

The TripleCheck broker is a central, global store for all of your contracts and contract tests.

399 lines 16.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TripleCheckBroker = exports.createNewBroker = void 0; const calculateDbKey_1 = require("../frameworks/calculateDbKey"); const messages_1 = require("../frameworks/messages"); const createNewBroker = (repository) => { return new TripleCheckBroker(repository); }; exports.createNewBroker = createNewBroker; class TripleCheckBroker { repository; constructor(repository) { this.repository = repository; } async router(url, payload) { const { method, pathname, search } = url; if (!method || !pathname) throw new Error(messages_1.errorRouterMissingParams); let responseData = 'DONE'; let status = 200; const errorResponse = 'Not a valid path...'; const path = pathname.substring(1, pathname.length); const query = (() => { if (search) { if (search[0] === '?') return search.substring(1, search.length).replace(/%40/g, '@'); else return search.replace(/%40/g, '@'); } })(); const key = (() => { if (!query) return ''; const [name, version] = query.split('@'); return (0, calculateDbKey_1.calculateDbKey)({ type: path, name, version }); })(); if (method === 'GET') { if (query) { if (path === 'tests') responseData = await this.getTests(query); else if (path === 'contracts') responseData = await this.getContracts(query); else if (path === 'services') responseData = await this.getServices(query); else if (path === 'dependencies' || path === 'dependents') responseData = await this.getRelations(path, key); } else if (!query) { if (path === 'tests') responseData = await this.getTests(); else if (path === 'contracts') responseData = await this.getContracts(); else if (path === 'services') responseData = await this.getServices(); else if (path === 'dependencies' || path === 'dependents') responseData = await this.getRelations(path); } } else if (method === 'POST' && path === 'publish') responseData = await this.publish(payload); else if (method === 'DELETE') { const { serviceName, version, test } = payload; if (path === 'tests') await this.deleteTest(serviceName, version, test); if (path === 'contracts') await this.deleteContract(serviceName, version); } else { responseData = errorResponse; status = 400; } return { responseData, status }; } async publish(data) { const { contracts, tests, dependencies, identity } = data; await this.updateRelations(identity, dependencies); await this.updateContracts(contracts); await this.updateTests(tests); return 'DONE'; } async getData(key) { if (!key) return this.handleError(messages_1.errorGetDataMissingKey); let data = await this.repository.getData(key); if ((!data && key === 'dependencies') || (!data && key === 'dependents')) data = {}; else if (!data) data = []; console.log((0, messages_1.msgFinishedGettingData)(key)); return data; } async updateData(key, data) { if (!key || !data) return this.handleError(messages_1.errorUpdateDataMissingData); await this.repository.updateData(key, data); console.log(messages_1.msgFinishedPuttingData); return data; } async deleteData(key) { await this.repository.deleteData(key); console.log(messages_1.msgFinishedDeletingData); } async deleteTest(serviceName, serviceVersion, testName) { if (!serviceName) throw new Error("Missing 'serviceName' in deleteData()!"); const key = (0, calculateDbKey_1.calculateDbKey)({ type: 'test', name: serviceName, version: serviceVersion }); const serviceData = await this.getData(key); if (!serviceData) return; const updatedTests = serviceData.filter((item) => { const _testName = Object.keys(item)[0]; if (testName && testName !== _testName) return item; }); const IS_UNCHANGED = JSON.stringify(updatedTests) === JSON.stringify(serviceData); if (IS_UNCHANGED) return; if (updatedTests.length === 0) { const listType = 'tests'; const listData = await this.getData(listType); if (!listData) return; const filteredData = listData.filter((item) => item !== `${serviceName}@${serviceVersion}`); await this.updateData(listType, filteredData); await this.deleteData(key); console.log((0, messages_1.msgFinishedDeletingTest)(key)); } else { await this.updateData(key, updatedTests); console.log(messages_1.msgFinishedUpdatingTests); } } async deleteContract(serviceName, version) { if (!serviceName || !version) throw new Error("Missing 'serviceName' and/or 'version' in deleteData()!"); const serviceId = `${serviceName}@${version}`; const listType = 'contracts'; const listData = await this.getData(listType); if (!listData) return; const filteredData = listData.filter((item) => item !== serviceId); await this.updateData(listType, filteredData); await this.updateList('services', [serviceId], true); await this.deleteTest(serviceName, version); const key = (0, calculateDbKey_1.calculateDbKey)({ type: 'contract', name: serviceName, version }); await this.deleteData(key); console.log((0, messages_1.msgFinishedDeletingContract)(key)); } async updateList(listName, services, removeServices = false) { const currentList = await this.getData(listName); let updatedList = []; if (removeServices) updatedList = currentList.filter((item) => !services.includes(item)); else updatedList = [...currentList, ...services]; updatedList = Array.from(new Set(updatedList)); await this.updateData(listName, updatedList); return updatedList; } handleError(message, status = 400) { return { responseData: JSON.stringify(message), status }; } async getContracts(serviceId) { const services = await this.getData('contracts'); const contractPromises = services.map(async (service) => { if (serviceId && service !== serviceId) return; const [name, version] = service.split('@'); const key = (0, calculateDbKey_1.calculateDbKey)({ type: 'contract', name, version }); const data = await this.getData(key); return { [name]: { [version]: data } }; }); let contracts = await Promise.all(contractPromises); contracts = contracts.filter((test) => test); let fixedContracts = {}; contracts.forEach((contract) => { const name = Object.keys(contract)[0]; const version = Object.keys(contract[name])[0]; if (!fixedContracts[name]) fixedContracts[name] = contract[name]; if (!fixedContracts[name][version]) fixedContracts[name][version] = contract[name][version]; }); return Object.entries(fixedContracts).map((item) => ({ [item[0]]: item[1] })); } async updateContracts(contracts) { const type = 'contract'; let contractIds = []; if (!contracts || contracts.length === 0) return; const contractPromises = contracts.map(async (contract) => { const name = Object.keys(contract)[0]; const version = Object.keys(contract[name])[0]; const data = contract[name][version]; if (!type || !name || !version || !data) { console.warn(messages_1.warnUpdateContractsMissingRequiredVariables); console.log(`---> type: ${type}, name: ${name}, version: ${version}, data: ${data}`); return; } contractIds.push(`${name}@${version}`); const key = (0, calculateDbKey_1.calculateDbKey)({ type, name, version }); await this.updateData(key, data); }); await Promise.all(contractPromises); await this.updateList('contracts', contractIds); } async getTests(serviceId) { const services = await this.getData('tests'); if (!services || services.length === 0) return []; const testPromises = services.map(async (service) => { if (serviceId && service !== serviceId) return; const [name, version] = service.split('@'); const key = (0, calculateDbKey_1.calculateDbKey)({ type: 'test', name, version }); const data = await this.getData(key); return { [name]: { [version]: data } }; }); let tests = await Promise.all(testPromises); tests = tests.filter((test) => test); let fixedTests = {}; tests.forEach((test) => { const name = Object.keys(test)[0]; const version = Object.keys(test[name])[0]; if (!fixedTests[name]) fixedTests[name] = test[name]; if (!fixedTests[name][version]) fixedTests[name][version] = test[name][version]; }); return Object.entries(fixedTests).map((item) => ({ [item[0]]: item[1] })); } async updateTests(tests) { const type = 'test'; const testIds = []; const testPromises = tests.map(async (test) => { const name = Object.keys(test)[0]; const version = Object.keys(test[name])[0]; if (!type || !name || !version) { console.warn(messages_1.warnUpdateTestsMissingRequiredVariables); console.log(`---> type: ${type}, name: ${name}, version: ${version}`); return; } const key = (0, calculateDbKey_1.calculateDbKey)({ type, name, version }); const updatedTests = {}; const existingData = (await this.getData(key)) || []; const newTests = test[name][version]; const addTests = (arr) => { if (!arr || arr.length === 0) return; arr.forEach((item) => { const testName = Object.keys(item)[0]; updatedTests[testName] = item[testName]; }); }; addTests(existingData); addTests(newTests); const cleanedTests = Object.entries(updatedTests).map((updatedTest) => { const [testName, testData] = updatedTest; return { [testName]: testData }; }); testIds.push(`${name}@${version}`); await this.updateData(key, cleanedTests); }); await Promise.all(testPromises); await this.updateList('tests', testIds); } async getRelations(type, key) { let data = await this.getData(type); if (!data || data.length === 0) return []; if (key) { key = key.split('#')[1]; const [service, version] = key.split('@'); let response = {}; if (!version || version === 'undefined') response = data[service]; else if (data[service]) response = data[service][version]; return response || {}; } return data || []; } async updateRelations(identity, dependencies) { const { name, version } = identity; await this.updateList('services', [`${name}@${version}`]); const currentDependencies = await this.getData('dependencies'); const updatedDependencies = this.updateDependencies(identity, dependencies, currentDependencies); await this.updateData('dependencies', updatedDependencies); const currentDependents = await this.getData('dependents'); const updatedDependents = this.updateDependents(identity, dependencies, currentDependents); await this.updateData('dependents', updatedDependents); } updateDependencies(identity, dependencies, currentDependencies) { const { name, version } = identity; let updatedDependencies = currentDependencies; if (dependencies && dependencies.length > 0) { dependencies.forEach((dependency) => { if (!updatedDependencies[name]) updatedDependencies[name] = { [version]: [dependency] }; else if (!updatedDependencies[name][version]) updatedDependencies[name][version] = [dependency]; else { const fixedDependencies = Array.from(new Set(dependencies)); fixedDependencies.sort(); updatedDependencies[name][version] = fixedDependencies; } }); } return updatedDependencies; } updateDependents(identity, dependencies, currentDependents) { const { name, version } = identity; const versionedName = `${name}@${version}`; let updatedDependents = currentDependents; if (dependencies && dependencies.length > 0) { dependencies.forEach((dependency) => { const [dependencyName, dependencyVersion] = dependency.split('@'); if (!updatedDependents[dependencyName]) updatedDependents[dependencyName] = { [dependencyVersion]: [versionedName] }; else if (!updatedDependents[dependencyName][dependencyVersion]) updatedDependents[dependencyName][dependencyVersion] = [versionedName]; else { const fixedDependents = Array.from(new Set(updatedDependents[dependencyName][dependencyVersion])); if (!fixedDependents.includes(versionedName)) fixedDependents.push(versionedName); fixedDependents.sort(); updatedDependents[dependencyName][dependencyVersion] = fixedDependents; } }); } return updatedDependents; } async getServices(service) { if (service) { const services = await this.getData('services'); const serviceRegex = new RegExp(service, 'gi'); let result = services.map((item) => { if (item.match(serviceRegex)) return item.split('@')[1]; }); result = result.filter((item) => item); if (!result || result.length === 0) { console.log(messages_1.msgUnknownService); return {}; } else { return { [service]: result }; } } else { let services = await this.getData('services'); services = services.sort(); let lastService = ''; let result = {}; services.forEach((item) => { const [name, version] = item.split('@'); if (lastService !== name) result[name] = [version]; else result[name] = [...result[name], version]; lastService = name; }); return result; } } } exports.TripleCheckBroker = TripleCheckBroker; //# sourceMappingURL=TripleCheckBroker.js.map