From d51e86f7582e9053f42557641c5f9d4e9ff2b4c0 Mon Sep 17 00:00:00 2001 From: Aljosha Koecher Date: Mon, 15 Jun 2020 18:43:36 +0200 Subject: [PATCH 01/16] Separated test into multiple files containing tests and data --- test/index.js | 66 ------------------ test/testConverting/expectedResults.js | 92 ++++++++++++++++++++++++++ test/testConverting/index.js | 49 ++++++++++++++ test/{ => testConverting}/test-data.js | 0 4 files changed, 141 insertions(+), 66 deletions(-) delete mode 100644 test/index.js create mode 100644 test/testConverting/expectedResults.js create mode 100644 test/testConverting/index.js rename test/{ => testConverting}/test-data.js (100%) diff --git a/test/index.js b/test/index.js deleted file mode 100644 index 6cf73bc..0000000 --- a/test/index.js +++ /dev/null @@ -1,66 +0,0 @@ -import { assert } from 'chai'; - -const SparqlResultConverter = require('../lib/sparql-result-converter'); -const testData = require('./test-data'); - -const resultConverter = new SparqlResultConverter(); - - -describe('The test', () => { - it('should test table-to-tree-conversion', () => { - // Object that defines the structure of the result - const resultObject = [ - { - objectToGroup: 'owner', - name: 'ownerName', - childRoot: 'pets' - } - ]; - - // Expected result: - const expectedResult = [ - { - ownerName: 'Peter', - pets: [ - { - petName: 'Rex', - petType: 'Dog' - } - ] - }, - { - ownerName: 'John', - pets: [ - { - petName: 'Lassie', - petType: 'Dog' - }, - { - petName: 'Oliver', - petType: 'Cat' - } - ] - }, - { - ownerName: 'Mary', - pets: [ - { - petName: 'Huey', - petType: 'Cat' - }, - { - petName: 'Dewey', - petType: 'Cat' - }, - { - petName: 'Louie', - petType: 'Cat' - } - ] - } - ]; - - const convertedResult = resultConverter.convert(testData.results, resultObject); - assert.deepEqual(convertedResult, expectedResult, 'Testing table-to-tree-conversion failed...'); - }); -}); diff --git a/test/testConverting/expectedResults.js b/test/testConverting/expectedResults.js new file mode 100644 index 0000000..b817faa --- /dev/null +++ b/test/testConverting/expectedResults.js @@ -0,0 +1,92 @@ +// Expected result for one layer mapping: +const expectedOneLayerResult = [ + { + ownerName: 'Peter', + pets: [ + { + petName: 'Rex', + petType: 'Dog' + } + ] + }, + { + ownerName: 'John', + pets: [ + { + petName: 'Lassie', + petType: 'Dog' + }, + { + petName: 'Oliver', + petType: 'Cat' + } + ] + }, + { + ownerName: 'Mary', + pets: [ + { + petName: 'Huey', + petType: 'Cat' + }, + { + petName: 'Dewey', + petType: 'Cat' + }, + { + petName: 'Louie', + petType: 'Cat' + } + ] + } +]; + +const expectedTwoLayerResult = [ + { + ownerName: 'Peter', + petTypes: [ + { + type: 'Dog', + animals: [ + { name: 'Rex' } + ] + } + ] + }, + { + ownerName: 'John', + petTypes: [ + { + type: 'Dog', + animals: [ + { name: 'Lassie' } + ] + }, + { + type: 'Cat', + animals: [ + { name: 'Oliver' } + ] + } + ] + }, + { + ownerName: 'Mary', + petTypes: [ + { + type: 'Cat', + animals: [ + { name: 'Huey' }, + { name: 'Dewey' }, + { name: 'Louie' }, + ] + } + ] + } +]; + + +module.exports = { + expectedOneLayerResult, + expectedTwoLayerResult +}; diff --git a/test/testConverting/index.js b/test/testConverting/index.js new file mode 100644 index 0000000..b59f99f --- /dev/null +++ b/test/testConverting/index.js @@ -0,0 +1,49 @@ +import { assert } from 'chai'; +import { expectedOneLayerResult, expectedTwoLayerResult } from './expectedResults'; + +const SparqlResultConverter = require('../../lib/sparql-result-converter'); +const testData = require('./test-data'); + +const resultConverter = new SparqlResultConverter(); + + +describe('One Layer Test', () => { + it('Should group a result on one layer', () => { + // Object that defines the structure of the result + const oneLayerMappingDefinition = [ + { + objectToGroup: 'owner', + name: 'ownerName', + childRoot: 'pets' + } + ]; + + const convertedResult = resultConverter.convert(testData.results, oneLayerMappingDefinition); + assert.deepEqual(convertedResult, expectedOneLayerResult, 'Testing one layer conversion failed...'); + }); +}); + +describe('Two Layer Test', () => { + it('Should group a result on two layers', () => { + // Object that defines the structure of the result + const twoLayerMappingDefinition = [ + { + objectToGroup: 'owner', + name: 'ownerName', + childRoot: 'petTypes' + }, + { + objectToGroup: 'petType', + name: 'animal', + childRoot: 'pets' + } + ]; + console.log('expected'); + console.log(expectedTwoLayerResult); + + const convertedResult = resultConverter.convert(testData.results, twoLayerMappingDefinition); + + + assert.deepEqual(convertedResult, expectedTwoLayerResult, 'Testing two layer conversion failed...'); + }); +}); diff --git a/test/test-data.js b/test/testConverting/test-data.js similarity index 100% rename from test/test-data.js rename to test/testConverting/test-data.js From 1f77a556d9a349643b7b0ff46a153d0a6355633b Mon Sep 17 00:00:00 2001 From: Aljosha Koecher Date: Tue, 16 Jun 2020 14:24:50 +0200 Subject: [PATCH 02/16] Migrated code to TypeScript --- .babelrc | 17 ---- .eslintrc | 15 --- .gitignore | 9 +- .vscode/launch.json | 46 +++++++++ .vscode/settings.json | 5 + package.json | 36 +++---- src/ArrayUtil.ts | 55 +++++++++++ src/SparqlResultConverter.ts | 100 ++++++++++++++++++++ src/array-util.js | 39 -------- src/sparql-result-converter.js | 95 ------------------- test/testConverting/expectedResults.js | 92 ------------------ test/testConverting/index.js | 49 ---------- test/testConverting/test-data.js | 94 ------------------ tests/testArrayUtil/ArrayUtil.test.ts | 47 +++++++++ tests/testConverting/expectedResults.ts | 86 +++++++++++++++++ tests/testConverting/test-data.ts | 92 ++++++++++++++++++ tests/testConverting/testConverting.test.ts | 46 +++++++++ tsconfig.json | 14 +++ 18 files changed, 514 insertions(+), 423 deletions(-) delete mode 100644 .babelrc delete mode 100644 .eslintrc create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 src/ArrayUtil.ts create mode 100644 src/SparqlResultConverter.ts delete mode 100644 src/array-util.js delete mode 100644 src/sparql-result-converter.js delete mode 100644 test/testConverting/expectedResults.js delete mode 100644 test/testConverting/index.js delete mode 100644 test/testConverting/test-data.js create mode 100644 tests/testArrayUtil/ArrayUtil.test.ts create mode 100644 tests/testConverting/expectedResults.ts create mode 100644 tests/testConverting/test-data.ts create mode 100644 tests/testConverting/testConverting.test.ts create mode 100644 tsconfig.json diff --git a/.babelrc b/.babelrc deleted file mode 100644 index ea9d8fd..0000000 --- a/.babelrc +++ /dev/null @@ -1,17 +0,0 @@ -{ - "plugins": ["transform-object-rest-spread"], - "env": { - "development": { - "presets": ["env"], - "plugins": [ - "add-module-exports" - ] - }, - "production": { - "presets": ["env", "minify"], - "plugins": [ - "add-module-exports" - ] - } - } -} diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index a5e9d63..0000000 --- a/.eslintrc +++ /dev/null @@ -1,15 +0,0 @@ -{ - "parser": "babel-eslint", - "extends": "airbnb", - "env": { - "mocha": true - }, - "rules": { - "comma-dangle": ["error", "only-multiline"], - "no-plusplus": "off", - "no-return-assign": ["error", "except-parens"], - "max-len": [2, 120, 2, {"ignoreComments": true}], - "prefer-destructuring": "off", - "no-param-reassign": "off" - } - } diff --git a/.gitignore b/.gitignore index 02c7823..d70577a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,10 @@ +# compiled output +/dist +/tmp +/out-tsc +# Only exists if Bazel was run +/bazel-out + # Logs logs *.log @@ -41,4 +48,4 @@ package-lock.json yarn.lock others -.DS_Store \ No newline at end of file +.DS_Store diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..72cd313 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,46 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Run mocha", + "type": "node", + "request": "launch", + "program": "${workspaceRoot}/node_modules/mocha/bin/_mocha", + "stopOnEntry": false, + "args": [ + "--require babel-register", + "--require babel-core/register", + "--require babel-polyfill", + " --recursive", + "--recursive", + "--no-timeouts" + ], + "cwd": "${workspaceRoot}", + "runtimeExecutable": null, + "env": { + "NODE_ENV": "testing" + } + }, + { + "name": "Attach", + "port": 9229, + "request": "attach", + "skipFiles": [ + "/**" + ], + "type": "pwa-node" + }, + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "skipFiles": [ + "/**" + ], + "program": "${workspaceFolder}\\lib\\sparql-result-converter.js" + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..e7f99cb --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "eslint.workingDirectories": [ + { "mode": "auto" } +], +} diff --git a/package.json b/package.json index c6ad005..e6abc61 100644 --- a/package.json +++ b/package.json @@ -3,15 +3,13 @@ "version": "1.0.2", "description": "Little utility function to that converts the table-like result of a SPARQL query into a JSON tree with a user-defined structure", "scripts": { - "clean": "rimraf lib", + "clean": "rimraf src", + "clean-node_modules": "rimraf node_modules", + "build": "tsc src", "test": "npm run lint && npm run cover", - "test:prod": "cross-env BABEL_ENV=production npm run test", - "test:only": "mocha --require babel-register --require babel-core/register --require babel-polyfill --recursive", - "test:watch": "npm test -- --watch", - "cover": "nyc --check-coverage npm run test:only", - "lint": "eslint src test", - "build": "cross-env BABEL_ENV=production babel src --out-dir lib", - "prepare": "npm run clean && npm run build &&npm run lint && npm run test" + "test:only": "mocha -r ts-node/register tests/**/*.test.ts", + "cover": "nyc -r lcov -e .ts -x \"*.test.ts\" npm run test", + "lint": "eslint src test/** --ext .ts" }, "files": [ "lib", @@ -39,25 +37,21 @@ "homepage": "https://github.com/aljoshakoecher/sparql-result-converter#readme", "dependencies": { "json-groupby": "^1.1.0", - "lodash": "^4.17.15" + "lodash.isempty": "^4.4.0" }, "devDependencies": { - "babel-cli": "^6.26.0", - "babel-eslint": "^10.0.1", - "babel-plugin-add-module-exports": "^1.0.0", - "babel-plugin-transform-object-rest-spread": "^6.26.0", - "babel-polyfill": "^6.26.0", - "babel-preset-env": "^1.6.1", - "babel-preset-minify": "0.3.0", + "@types/chai": "^4.2.11", + "@types/lodash.isempty": "^4.4.6", + "@types/mocha": "^7.0.2", + "@typescript-eslint/eslint-plugin": "^3.3.0", + "@typescript-eslint/parser": "^3.3.0", "chai": "^4.1.2", - "cross-env": "^5.1.3", "eslint": "^5.16.0", - "eslint-config-airbnb": "^17.1.0", "eslint-plugin-import": "^2.7.0", - "eslint-plugin-jsx-a11y": "^6.0.2", - "eslint-plugin-react": "^7.4.0", "mocha": "^6.1.3", "nyc": "^13.3.0", - "rimraf": "^2.6.2" + "rimraf": "^2.6.2", + "ts-node": "^8.10.2", + "typescript": "^3.9.5" } } diff --git a/src/ArrayUtil.ts b/src/ArrayUtil.ts new file mode 100644 index 0000000..73ebb93 --- /dev/null +++ b/src/ArrayUtil.ts @@ -0,0 +1,55 @@ +export class ArrayUtil { + + /** + * Checks whether or not all entries of the array contain the property that is used for grouping + * @param {*} arrayToCheck + * @param {*} groupingProperty + */ + static allEntriesContainGroupingProperty(arrayToCheck, groupingProperty) { + for (let i = 0; i < arrayToCheck.length; i++) { + const element = arrayToCheck[i]; + if (!Object.prototype.hasOwnProperty.call(element, groupingProperty)) { + return false; + } + } + return true; + } + + + + /** + * Transforms an array of objects to an array of simple datatypes by extracting every value-property. + * @param {*} sparqlResult Array of objects that contain a value-property + */ + static extractValues(sparqlResult: SparqlResultLine[]): TransformedSparqlResultElement[] { + + const outputArray = new Array(); + + // Take every array element and extract all values of all object keys -> flatten the array + sparqlResult.forEach((sparqlResultLine:SparqlResultLine) => { + const objectKeys = Object.keys(sparqlResultLine); + + const outputElement = {}; + objectKeys.forEach((key) => { + outputElement[key] = sparqlResultLine[key].value; + }); + outputArray.push(outputElement); + }); + + return outputArray; + } + + +} + +export interface SparqlResultLine { + [name: string]: { + type: string, + value: string + } +} + +export interface TransformedSparqlResultElement { + [propName: string]: string; +} + diff --git a/src/SparqlResultConverter.ts b/src/SparqlResultConverter.ts new file mode 100644 index 0000000..666f795 --- /dev/null +++ b/src/SparqlResultConverter.ts @@ -0,0 +1,100 @@ +import groupBy = require('json-groupby') +// import { groupby} from "json-groupby"; +import { isEmpty } from "lodash"; +import { ArrayUtil, SparqlResultLine } from "./ArrayUtil"; + +// Maps the query result of "select_allModules" to an array of Modules +export class SparqlResultConverter { + /** + * Groups a table-structure and converts it to a tree-like structure + * @param {*} inputArray An array representing data structured as a table + * @param {*} mappingDefinitions An array of objects representing the structure of the final output + */ + convert(inputArray: SparqlResultLine[], mappingDefinitions: MappingDefinition[], currElement = 0) { + let outputArray; + + // first: transform array + if (currElement === 0) { + outputArray = ArrayUtil.extractValues(inputArray); + } + + + // get currrent element and fix child root + const currGroup = mappingDefinitions[currElement]; + + // Fix childRoot if its not passed in. TODO: Remove this... Should always be passed + // currGroup.childRoot = typeof currGroup.childRoot === 'undefined' ? 'content' : currGroup.childRoot; + + // group the ungrouped outputArray + const groupedArray = groupBy(outputArray, [currGroup.objectToGroup]); + + // Empty the outputArray array, it will later be filled with the grouped content + outputArray = []; + + Object.keys(groupedArray).forEach((key) => { + let groupedElement = groupedArray[key]; + + // Collect all elements that should be collected + // TODO: Not only take groupedElement[0], but make sure the properties to collect are equal for all groupedElements + const elemsToCollect = {}; + if (Object.prototype.hasOwnProperty.call(currGroup, 'toCollect')) { + currGroup['toCollect'].forEach((elemToCollect) => { + elemsToCollect[elemToCollect] = groupedElement[0][elemToCollect]; + groupedElement.forEach((inputElem) => { + delete inputElem[elemToCollect]; + }); + }); + } + + + if (currElement <= (mappingDefinitions.length - 2)) { + if (ArrayUtil.allEntriesContainGroupingProperty(groupedElement, mappingDefinitions[currElement + 1].objectToGroup)) { + groupedElement = (this.convert(groupedElement, mappingDefinitions, currElement + 1)); + } + } + + + // Delete the all elements that have already been grouped + groupedElement.forEach((element) => { + mappingDefinitions.forEach((group) => { + delete element[group.objectToGroup]; + }); + }); + + + const nameToPush = { + [currGroup.name]: key, + }; + + let objToPush = {}; + if (!isEmpty(groupedElement[0])) { + const groupToPush = { + [currGroup.childRoot]: groupedElement + }; + objToPush = { + ...nameToPush, + ...elemsToCollect, + ...groupToPush + }; + } else { + objToPush = { + ...nameToPush, + ...elemsToCollect + }; + } + + + // Add the grouped element to the inputArray + outputArray.push(objToPush); + }); + + return outputArray; + } +} + + +interface MappingDefinition { + objectToGroup: string, + name: string, + childRoot: string +} diff --git a/src/array-util.js b/src/array-util.js deleted file mode 100644 index d22bcd7..0000000 --- a/src/array-util.js +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Checks whether or not all entries of the array contain the property that is used for grouping - * @param {*} arrayToCheck - * @param {*} groupingProperty - */ -function allEntriesContainGroupingProperty(arrayToCheck, groupingProperty) { - for (let i = 0; i < arrayToCheck.length; i++) { - const element = arrayToCheck[i]; - if (!Object.prototype.hasOwnProperty.call(element, groupingProperty)) { - return false; - } - } - return true; -} - -/** - * Transforms an array of objects to an array of simple datatypes by extracting every value-property. - * @param {*} inputArray Array of objects that contain a value-property - */ -function transformArray(inputArray) { - const transformedArray = inputArray; - - // Take every array element and extract all values of all object keys -> flatten the array - transformedArray.forEach((arrayObject) => { - const objectKeys = Object.keys(arrayObject); - - objectKeys.forEach((key) => { - arrayObject[key] = arrayObject[key].value; - }); - }); - - return transformedArray; -} - - -module.exports = { - allEntriesContainGroupingProperty, - transformArray -}; diff --git a/src/sparql-result-converter.js b/src/sparql-result-converter.js deleted file mode 100644 index 344d905..0000000 --- a/src/sparql-result-converter.js +++ /dev/null @@ -1,95 +0,0 @@ -const groupBy = require('json-groupby'); -const _ = require('lodash'); - -const transformArray = require('./array-util').transformArray; -const allEntriesContainGroupingProperty = require('./array-util').allEntriesContainGroupingProperty; - -// Maps the query result of "select_allModules" to an array of Modules -class SparqlResultConverter { - /** - * Groups a table-structure and converts it to a tree-like structure - * @param {*} inputArray An array representing data structured as a table - * @param {*} treeModel An object representing the final output (as a tree-structure) - */ - convert(inputArray, treeModel, currElement = 0) { - let outputArray; - - // first: transform array - if (currElement === 0) { - outputArray = transformArray(inputArray); - } - - - // get currrent element and fix child root - const currGroup = treeModel[currElement]; - currGroup.childRoot = typeof currGroup.childRoot === 'undefined' ? 'content' : currGroup.childRoot; - - // group the ungrouped outputArray - const groupedArray = groupBy(outputArray, [currGroup.objectToGroup]); - - // Empty the outputArray array, it will later be filled with the grouped content - outputArray = []; - - Object.keys(groupedArray).forEach((key) => { - let groupedElement = groupedArray[key]; - - // Collect all elements that should be collected - // TODO: Not only take groupedElement[0], but make sure the properties to collect are equal for all groupedElements - const elemsToCollect = {}; - if (Object.prototype.hasOwnProperty.call(currGroup, 'toCollect')) { - currGroup.toCollect.forEach((elemToCollect) => { - elemsToCollect[elemToCollect] = groupedElement[0][elemToCollect]; - groupedElement.forEach((inputElem) => { - delete inputElem[elemToCollect]; - }); - }); - } - - - if (currElement <= (treeModel.length - 2)) { - if (allEntriesContainGroupingProperty(groupedElement, treeModel[currElement + 1].objectToGroup)) { - groupedElement = (this.convert(groupedElement, treeModel, currElement + 1)); - } - } - - - // Delete the all elements that have already been grouped - groupedElement.forEach((element) => { - treeModel.forEach((group) => { - delete element[group.objectToGroup]; - }); - }); - - - const nameToPush = { - [currGroup.name]: key, - }; - - let objToPush = {}; - if (!_.isEmpty(groupedElement[0])) { - const groupToPush = { - [currGroup.childRoot]: groupedElement - }; - objToPush = { - ...nameToPush, - ...elemsToCollect, - ...groupToPush - }; - } else { - objToPush = { - ...nameToPush, - ...elemsToCollect - }; - } - - - // Add the grouped element to the inputArray - outputArray.push(objToPush); - }); - - return outputArray; - } -} - - -module.exports = SparqlResultConverter; diff --git a/test/testConverting/expectedResults.js b/test/testConverting/expectedResults.js deleted file mode 100644 index b817faa..0000000 --- a/test/testConverting/expectedResults.js +++ /dev/null @@ -1,92 +0,0 @@ -// Expected result for one layer mapping: -const expectedOneLayerResult = [ - { - ownerName: 'Peter', - pets: [ - { - petName: 'Rex', - petType: 'Dog' - } - ] - }, - { - ownerName: 'John', - pets: [ - { - petName: 'Lassie', - petType: 'Dog' - }, - { - petName: 'Oliver', - petType: 'Cat' - } - ] - }, - { - ownerName: 'Mary', - pets: [ - { - petName: 'Huey', - petType: 'Cat' - }, - { - petName: 'Dewey', - petType: 'Cat' - }, - { - petName: 'Louie', - petType: 'Cat' - } - ] - } -]; - -const expectedTwoLayerResult = [ - { - ownerName: 'Peter', - petTypes: [ - { - type: 'Dog', - animals: [ - { name: 'Rex' } - ] - } - ] - }, - { - ownerName: 'John', - petTypes: [ - { - type: 'Dog', - animals: [ - { name: 'Lassie' } - ] - }, - { - type: 'Cat', - animals: [ - { name: 'Oliver' } - ] - } - ] - }, - { - ownerName: 'Mary', - petTypes: [ - { - type: 'Cat', - animals: [ - { name: 'Huey' }, - { name: 'Dewey' }, - { name: 'Louie' }, - ] - } - ] - } -]; - - -module.exports = { - expectedOneLayerResult, - expectedTwoLayerResult -}; diff --git a/test/testConverting/index.js b/test/testConverting/index.js deleted file mode 100644 index b59f99f..0000000 --- a/test/testConverting/index.js +++ /dev/null @@ -1,49 +0,0 @@ -import { assert } from 'chai'; -import { expectedOneLayerResult, expectedTwoLayerResult } from './expectedResults'; - -const SparqlResultConverter = require('../../lib/sparql-result-converter'); -const testData = require('./test-data'); - -const resultConverter = new SparqlResultConverter(); - - -describe('One Layer Test', () => { - it('Should group a result on one layer', () => { - // Object that defines the structure of the result - const oneLayerMappingDefinition = [ - { - objectToGroup: 'owner', - name: 'ownerName', - childRoot: 'pets' - } - ]; - - const convertedResult = resultConverter.convert(testData.results, oneLayerMappingDefinition); - assert.deepEqual(convertedResult, expectedOneLayerResult, 'Testing one layer conversion failed...'); - }); -}); - -describe('Two Layer Test', () => { - it('Should group a result on two layers', () => { - // Object that defines the structure of the result - const twoLayerMappingDefinition = [ - { - objectToGroup: 'owner', - name: 'ownerName', - childRoot: 'petTypes' - }, - { - objectToGroup: 'petType', - name: 'animal', - childRoot: 'pets' - } - ]; - console.log('expected'); - console.log(expectedTwoLayerResult); - - const convertedResult = resultConverter.convert(testData.results, twoLayerMappingDefinition); - - - assert.deepEqual(convertedResult, expectedTwoLayerResult, 'Testing two layer conversion failed...'); - }); -}); diff --git a/test/testConverting/test-data.js b/test/testConverting/test-data.js deleted file mode 100644 index 5f15629..0000000 --- a/test/testConverting/test-data.js +++ /dev/null @@ -1,94 +0,0 @@ -/** - * Mock-up of a piece of data that could be returned from a DB-Query - */ -const testData = { - head: ['owner', 'petName', 'petType'], - results: [ - { - owner: { - type: 'String', - value: 'Peter', - }, - petName: { - type: 'String', - value: 'Rex' - }, - petType: { - type: 'String', - value: 'Dog' - } - }, - { - owner: { - type: 'String', - value: 'John', - }, - petName: { - type: 'String', - value: 'Lassie' - }, - petType: { - type: 'String', - value: 'Dog' - } - }, - { - owner: { - type: 'String', - value: 'John', - }, - petName: { - type: 'String', - value: 'Oliver' - }, - petType: { - type: 'String', - value: 'Cat' - } - }, - { - owner: { - type: 'String', - value: 'Mary', - }, - petName: { - type: 'String', - value: 'Huey' - }, - petType: { - type: 'String', - value: 'Cat' - } - }, - { - owner: { - type: 'String', - value: 'Mary', - }, - petName: { - type: 'String', - value: 'Dewey' - }, - petType: { - type: 'String', - value: 'Cat' - } - }, - { - owner: { - type: 'String', - value: 'Mary', - }, - petName: { - type: 'String', - value: 'Louie' - }, - petType: { - type: 'String', - value: 'Cat' - } - }, - ] -}; - -export default testData; diff --git a/tests/testArrayUtil/ArrayUtil.test.ts b/tests/testArrayUtil/ArrayUtil.test.ts new file mode 100644 index 0000000..73478f0 --- /dev/null +++ b/tests/testArrayUtil/ArrayUtil.test.ts @@ -0,0 +1,47 @@ +import { assert } from 'chai'; +import { ArrayUtil, SparqlResultLine } from '../../src/ArrayUtil'; + + +describe('ArrayUtil Test', () => { + it('Should extract value property of each entry', () => { + // Object that defines the structure of the result + const input : SparqlResultLine[] = + [ + { + "capability": { + "type": "uri", + "value": "http://www.hsu-ifa.de/ontologies/capability-example#FraesenCapability" + }, + "skill": { + "type": "uri", + "value": "http://www.hsu-ifa.de/ontologies/capability-example#FraesenSkill" + } + }, + { + "capability": { + "type": "uri", + "value": "http://www.hsu-ifa.de/ontologies/capability-example#FraesenCapability" + }, + "skill": { + "type": "uri", + "value": "http://www.hsu-ifa.de/ontologies/capability-example#FraesenSkill_REST" + } + } + ]; + + const expectedResult = [ + { + capability: "http://www.hsu-ifa.de/ontologies/capability-example#FraesenCapability", + skill: "http://www.hsu-ifa.de/ontologies/capability-example#FraesenSkill" + }, + { + capability: "http://www.hsu-ifa.de/ontologies/capability-example#FraesenCapability", + skill: "http://www.hsu-ifa.de/ontologies/capability-example#FraesenSkill_REST" + } + ]; + + + const transformedArray = ArrayUtil.extractValues(input); + assert.deepEqual(transformedArray, expectedResult, 'Expected result should have all values extracted...'); + }); +}); diff --git a/tests/testConverting/expectedResults.ts b/tests/testConverting/expectedResults.ts new file mode 100644 index 0000000..7db4430 --- /dev/null +++ b/tests/testConverting/expectedResults.ts @@ -0,0 +1,86 @@ +// Expected result for one layer mapping: +export const expectedOneLayerResult = [ + { + ownerName: 'Peter', + pets: [ + { + petName: 'Rex', + petType: 'Dog' + } + ] + }, + { + ownerName: 'John', + pets: [ + { + petName: 'Lassie', + petType: 'Dog' + }, + { + petName: 'Oliver', + petType: 'Cat' + } + ] + }, + { + ownerName: 'Mary', + pets: [ + { + petName: 'Huey', + petType: 'Cat' + }, + { + petName: 'Dewey', + petType: 'Cat' + }, + { + petName: 'Louie', + petType: 'Cat' + } + ] + } +]; + +export const expectedTwoLayerResult = [ + { + ownerName: 'Peter', + petTypes: [ + { + type: 'Dog', + animals: [ + { name: 'Rex' } + ] + } + ] + }, + { + ownerName: 'John', + petTypes: [ + { + type: 'Dog', + animals: [ + { name: 'Lassie' } + ] + }, + { + type: 'Cat', + animals: [ + { name: 'Oliver' } + ] + } + ] + }, + { + ownerName: 'Mary', + petTypes: [ + { + type: 'Cat', + animals: [ + { name: 'Huey' }, + { name: 'Dewey' }, + { name: 'Louie' }, + ] + } + ] + } +]; diff --git a/tests/testConverting/test-data.ts b/tests/testConverting/test-data.ts new file mode 100644 index 0000000..78f45a6 --- /dev/null +++ b/tests/testConverting/test-data.ts @@ -0,0 +1,92 @@ +/** + * Mock-up of a piece of data that could be returned from a DB-Query + */ +export const testData = { + head: ['owner', 'petName', 'petType'], + results: [ + { + owner: { + type: 'String', + value: 'Peter', + }, + petName: { + type: 'String', + value: 'Rex' + }, + petType: { + type: 'String', + value: 'Dog' + } + }, + { + owner: { + type: 'String', + value: 'John', + }, + petName: { + type: 'String', + value: 'Lassie' + }, + petType: { + type: 'String', + value: 'Dog' + } + }, + { + owner: { + type: 'String', + value: 'John', + }, + petName: { + type: 'String', + value: 'Oliver' + }, + petType: { + type: 'String', + value: 'Cat' + } + }, + { + owner: { + type: 'String', + value: 'Mary', + }, + petName: { + type: 'String', + value: 'Huey' + }, + petType: { + type: 'String', + value: 'Cat' + } + }, + { + owner: { + type: 'String', + value: 'Mary', + }, + petName: { + type: 'String', + value: 'Dewey' + }, + petType: { + type: 'String', + value: 'Cat' + } + }, + { + owner: { + type: 'String', + value: 'Mary', + }, + petName: { + type: 'String', + value: 'Louie' + }, + petType: { + type: 'String', + value: 'Cat' + } + }, + ] +}; diff --git a/tests/testConverting/testConverting.test.ts b/tests/testConverting/testConverting.test.ts new file mode 100644 index 0000000..e85817c --- /dev/null +++ b/tests/testConverting/testConverting.test.ts @@ -0,0 +1,46 @@ +import { assert } from 'chai'; +import { expectedOneLayerResult, expectedTwoLayerResult } from './expectedResults'; + +import { SparqlResultConverter } from "../../src/SparqlResultConverter"; + +import {testData} from './test-data'; + +const resultConverter = new SparqlResultConverter(); + + +describe('One Layer Test', () => { + it('Should group a result on one layer', () => { + // Object that defines the structure of the result + const oneLayerMappingDefinition = [ + { + objectToGroup: 'owner', + name: 'ownerName', + childRoot: 'pets' + } + ]; + + const convertedResult = resultConverter.convert(testData.results, oneLayerMappingDefinition); + assert.deepEqual(convertedResult, expectedOneLayerResult, 'Testing one layer conversion failed...'); + }); +}); + +describe('Two Layer Test', () => { + it('Should group a result on two layers', () => { + // Object that defines the structure of the result + const twoLayerMappingDefinition = [ + { + objectToGroup: 'owner', + name: 'ownerName', + childRoot: 'petTypes' + }, + { + objectToGroup: 'petType', + name: 'animal', + childRoot: 'pets' + } + ]; + const convertedResult = resultConverter.convert(testData.results, twoLayerMappingDefinition); + + assert.deepEqual(convertedResult, expectedTwoLayerResult, 'Testing two layer conversion failed...'); + }); +}); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..3c9c192 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + /* Truncated compiler options to list only relevant options */ + "declaration": true, + "declarationMap": true, + "outDir": "./dist", + "composite": true, + "rootDir": ".", + "baseUrl": "./", + "module": "CommonJS", + "target": "es2017", + }, + "exclude": ["dist", "node_modules"] + } From 86aa166710f3f007019b524f24d180d3322bb2d6 Mon Sep 17 00:00:00 2001 From: Aljosha Koecher Date: Tue, 16 Jun 2020 14:25:01 +0200 Subject: [PATCH 03/16] Added ESLint --- .eslintignore | 10 ++++++++++ .eslintrc.js | 22 ++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 .eslintignore create mode 100644 .eslintrc.js diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..1c7e978 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,10 @@ +!**/.eslintrc* +node_modules* +dist +*.svg +*.ico +*.json +.gitignore +*.md +*.log +*.lock diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..900b1a4 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,22 @@ + +/* eslint-disable no-undef */ +module.exports = { + parser: '@typescript-eslint/parser', // Specifies the ESLint parser + extends: [ + "eslint:recommended", // Uses the recommended rules from the @typescript-eslint/eslint-plugin + // "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/eslint-recommended", + ], + parserOptions: { + ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features + sourceType: 'module', // Allows for the use of imports + }, + rules: { + "semi": ["error","always"], + "indent": ["error", 4], + "prefer-const": ["error",{}], + "max-len": ["error", {code: 140, ignoreComments: true}] + // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs + // e.g. "@typescript-eslint/explicit-function-return-type": "off", + }, +}; From ea50a21afbdb965b3e5e9dbd1d665978fa1b028a Mon Sep 17 00:00:00 2001 From: Aljosha Koecher Date: Tue, 16 Jun 2020 17:17:08 +0200 Subject: [PATCH 04/16] Updated ncy and eslint fixing some problems with both, added another recommended ruleset to .eslintrc --- .eslintrc.js | 3 ++- package.json | 12 ++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 900b1a4..864f46a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,11 +1,12 @@ /* eslint-disable no-undef */ module.exports = { + root: true, parser: '@typescript-eslint/parser', // Specifies the ESLint parser extends: [ "eslint:recommended", // Uses the recommended rules from the @typescript-eslint/eslint-plugin - // "plugin:@typescript-eslint/recommended", "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", ], parserOptions: { ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features diff --git a/package.json b/package.json index e6abc61..97b42d5 100644 --- a/package.json +++ b/package.json @@ -6,10 +6,10 @@ "clean": "rimraf src", "clean-node_modules": "rimraf node_modules", "build": "tsc src", - "test": "npm run lint && npm run cover", + "test": "npm run lint && npm run coverage", "test:only": "mocha -r ts-node/register tests/**/*.test.ts", - "cover": "nyc -r lcov -e .ts -x \"*.test.ts\" npm run test", - "lint": "eslint src test/** --ext .ts" + "coverage": "nyc npm run test:only", + "lint": "eslint src tests/**/* --ext .ts" }, "files": [ "lib", @@ -36,7 +36,7 @@ }, "homepage": "https://github.com/aljoshakoecher/sparql-result-converter#readme", "dependencies": { - "json-groupby": "^1.1.0", + "lodash.groupby": "^4.6.0", "lodash.isempty": "^4.4.0" }, "devDependencies": { @@ -46,10 +46,10 @@ "@typescript-eslint/eslint-plugin": "^3.3.0", "@typescript-eslint/parser": "^3.3.0", "chai": "^4.1.2", - "eslint": "^5.16.0", + "eslint": "^6.8.0", "eslint-plugin-import": "^2.7.0", "mocha": "^6.1.3", - "nyc": "^13.3.0", + "nyc": "^15.1.0", "rimraf": "^2.6.2", "ts-node": "^8.10.2", "typescript": "^3.9.5" From 097e33e12ea17b16620d2ece524a852edac167e3 Mon Sep 17 00:00:00 2001 From: Aljosha Koecher Date: Tue, 16 Jun 2020 17:17:16 +0200 Subject: [PATCH 05/16] Added debug config --- .vscode/launch.json | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 72cd313..867b969 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,24 +5,20 @@ "version": "0.2.0", "configurations": [ { - "name": "Run mocha", - "type": "node", - "request": "launch", - "program": "${workspaceRoot}/node_modules/mocha/bin/_mocha", - "stopOnEntry": false, - "args": [ - "--require babel-register", - "--require babel-core/register", - "--require babel-polyfill", - " --recursive", - "--recursive", - "--no-timeouts" - ], - "cwd": "${workspaceRoot}", - "runtimeExecutable": null, - "env": { - "NODE_ENV": "testing" - } + "type": "node", + "request": "launch", + "name": "Mocha Current File", + "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", + "args": [ + "--no-timeouts", + "--colors", + "${file}", + "--require", + "ts-node/register" + ], + "console": "integratedTerminal", + "sourceMaps": true, + "internalConsoleOptions": "neverOpen" }, { "name": "Attach", From 251d89e0edaffd87a205a8962ca10d17ce84de92 Mon Sep 17 00:00:00 2001 From: Aljosha Koecher Date: Tue, 16 Jun 2020 17:18:00 +0200 Subject: [PATCH 06/16] Added some tests for util functions and fixed problems with test data --- tests/testArrayUtil/ArrayUtil.test.ts | 93 ++++++++++++++++----- tests/testConverting/expectedResults.ts | 20 ++--- tests/testConverting/testConverting.test.ts | 2 +- 3 files changed, 81 insertions(+), 34 deletions(-) diff --git a/tests/testArrayUtil/ArrayUtil.test.ts b/tests/testArrayUtil/ArrayUtil.test.ts index 73478f0..92cf6ea 100644 --- a/tests/testArrayUtil/ArrayUtil.test.ts +++ b/tests/testArrayUtil/ArrayUtil.test.ts @@ -5,29 +5,29 @@ import { ArrayUtil, SparqlResultLine } from '../../src/ArrayUtil'; describe('ArrayUtil Test', () => { it('Should extract value property of each entry', () => { // Object that defines the structure of the result - const input : SparqlResultLine[] = - [ - { - "capability": { - "type": "uri", - "value": "http://www.hsu-ifa.de/ontologies/capability-example#FraesenCapability" - }, - "skill": { - "type": "uri", - "value": "http://www.hsu-ifa.de/ontologies/capability-example#FraesenSkill" - } - }, - { - "capability": { - "type": "uri", - "value": "http://www.hsu-ifa.de/ontologies/capability-example#FraesenCapability" - }, - "skill": { - "type": "uri", - "value": "http://www.hsu-ifa.de/ontologies/capability-example#FraesenSkill_REST" - } - } - ]; + const input: SparqlResultLine[] = + [ + { + "capability": { + "type": "uri", + "value": "http://www.hsu-ifa.de/ontologies/capability-example#FraesenCapability" + }, + "skill": { + "type": "uri", + "value": "http://www.hsu-ifa.de/ontologies/capability-example#FraesenSkill" + } + }, + { + "capability": { + "type": "uri", + "value": "http://www.hsu-ifa.de/ontologies/capability-example#FraesenCapability" + }, + "skill": { + "type": "uri", + "value": "http://www.hsu-ifa.de/ontologies/capability-example#FraesenSkill_REST" + } + } + ]; const expectedResult = [ { @@ -44,4 +44,51 @@ describe('ArrayUtil Test', () => { const transformedArray = ArrayUtil.extractValues(input); assert.deepEqual(transformedArray, expectedResult, 'Expected result should have all values extracted...'); }); + + + it('Should confirm that all array entries contain grouping property', () => { + // Just some random array + const input = + [ + { + name: "Peter", + age: 55 + }, + { + name: "John", + age: 43 + }, + { + name: "Mary", + age: 29 + } + ]; + + const result = ArrayUtil.allEntriesContainGroupingProperty(input, "name"); + assert.isTrue(result, 'Should return true because all array entries contain grouping property...'); + }); + + + it('Should confirm that not all array entries contain grouping property', () => { + // Just some random array + const input = + [ + { + name: "Peter", + age: 55, + city: "Boston" + }, + { + name: "John", + age: 43, + city: "New York City" + }, + { + name: "Mary", + age: 29 + } + ]; + const result = ArrayUtil.allEntriesContainGroupingProperty(input, "city"); + assert.isFalse(result, 'Should return false because not all array entries contain grouping property...'); + }); }); diff --git a/tests/testConverting/expectedResults.ts b/tests/testConverting/expectedResults.ts index 7db4430..53c4986 100644 --- a/tests/testConverting/expectedResults.ts +++ b/tests/testConverting/expectedResults.ts @@ -47,8 +47,8 @@ export const expectedTwoLayerResult = [ petTypes: [ { type: 'Dog', - animals: [ - { name: 'Rex' } + pets: [ + { petName: 'Rex' } ] } ] @@ -58,14 +58,14 @@ export const expectedTwoLayerResult = [ petTypes: [ { type: 'Dog', - animals: [ - { name: 'Lassie' } + pets: [ + { petName: 'Lassie' } ] }, { type: 'Cat', - animals: [ - { name: 'Oliver' } + pets: [ + { petName: 'Oliver' } ] } ] @@ -75,10 +75,10 @@ export const expectedTwoLayerResult = [ petTypes: [ { type: 'Cat', - animals: [ - { name: 'Huey' }, - { name: 'Dewey' }, - { name: 'Louie' }, + pets: [ + { petName: 'Huey' }, + { petName: 'Dewey' }, + { petName: 'Louie' }, ] } ] diff --git a/tests/testConverting/testConverting.test.ts b/tests/testConverting/testConverting.test.ts index e85817c..0ceb7f3 100644 --- a/tests/testConverting/testConverting.test.ts +++ b/tests/testConverting/testConverting.test.ts @@ -35,7 +35,7 @@ describe('Two Layer Test', () => { }, { objectToGroup: 'petType', - name: 'animal', + name: 'type', childRoot: 'pets' } ]; From dae5066ebd21bf3ffcdfadb17a3a649c901b93bf Mon Sep 17 00:00:00 2001 From: Aljosha Koecher Date: Tue, 16 Jun 2020 17:18:20 +0200 Subject: [PATCH 07/16] Added nyc config --- .nycrc | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .nycrc diff --git a/.nycrc b/.nycrc new file mode 100644 index 0000000..b16c68d --- /dev/null +++ b/.nycrc @@ -0,0 +1,27 @@ +{ + "cache": false, + "check-coverage": false, + "extension": [ + ".ts" + ], + "include": [ + "**/*.js", + "**/*.ts" + ], + "exclude": [ + "coverage/**", + "node_modules/**", + "**/*.d.ts", + "**/*.test.ts", + "tests/*", + ".eslintrc.js" + ], + "sourceMap": true, + "reporter": [ + "html", + "text", + "text-summary" + ], + "all": true, + "instrument": true +} From 097c18789548bd144b993febf19e7ec0050ba89c Mon Sep 17 00:00:00 2001 From: Aljosha Koecher Date: Tue, 16 Jun 2020 17:18:50 +0200 Subject: [PATCH 08/16] Fixed bug that caused multiple groupings to fail, minor renamings --- src/SparqlResultConverter.ts | 58 +++++++++++++++++------------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/src/SparqlResultConverter.ts b/src/SparqlResultConverter.ts index 666f795..3bd958a 100644 --- a/src/SparqlResultConverter.ts +++ b/src/SparqlResultConverter.ts @@ -1,44 +1,41 @@ -import groupBy = require('json-groupby') -// import { groupby} from "json-groupby"; +import { groupBy } from "lodash"; import { isEmpty } from "lodash"; import { ArrayUtil, SparqlResultLine } from "./ArrayUtil"; // Maps the query result of "select_allModules" to an array of Modules export class SparqlResultConverter { /** - * Groups a table-structure and converts it to a tree-like structure - * @param {*} inputArray An array representing data structured as a table - * @param {*} mappingDefinitions An array of objects representing the structure of the final output - */ - convert(inputArray: SparqlResultLine[], mappingDefinitions: MappingDefinition[], currElement = 0) { - let outputArray; + * Groups a table-structure and converts it to a tree-like structure + * @param {*} inputArray An array representing data structured as a table + * @param {*} mappingDefinitions An array of objects representing the structure of the final output + */ + convert(inputArray: SparqlResultLine[], mappingDefinitions: MappingDefinition[], currElement = 0): Record[] { + let flattenedArray; // first: transform array if (currElement === 0) { - outputArray = ArrayUtil.extractValues(inputArray); + flattenedArray = ArrayUtil.extractValues(inputArray); + } else { + flattenedArray = inputArray; } + // get the current mapping object + const currentMappingDefition = mappingDefinitions[currElement]; - // get currrent element and fix child root - const currGroup = mappingDefinitions[currElement]; - - // Fix childRoot if its not passed in. TODO: Remove this... Should always be passed - // currGroup.childRoot = typeof currGroup.childRoot === 'undefined' ? 'content' : currGroup.childRoot; - - // group the ungrouped outputArray - const groupedArray = groupBy(outputArray, [currGroup.objectToGroup]); + // group the flattened array by the current mapping object's "objectToGroup" property + const groupedObject = groupBy(flattenedArray, (elem) => elem[currentMappingDefition.objectToGroup]); // Empty the outputArray array, it will later be filled with the grouped content - outputArray = []; + const outputArray = []; - Object.keys(groupedArray).forEach((key) => { - let groupedElement = groupedArray[key]; + Object.keys(groupedObject).forEach((key) => { + let groupedElement = groupedObject[key]; // Collect all elements that should be collected // TODO: Not only take groupedElement[0], but make sure the properties to collect are equal for all groupedElements const elemsToCollect = {}; - if (Object.prototype.hasOwnProperty.call(currGroup, 'toCollect')) { - currGroup['toCollect'].forEach((elemToCollect) => { + if(currentMappingDefition.toCollect) { + currentMappingDefition.toCollect.forEach((elemToCollect) => { elemsToCollect[elemToCollect] = groupedElement[0][elemToCollect]; groupedElement.forEach((inputElem) => { delete inputElem[elemToCollect]; @@ -56,20 +53,20 @@ export class SparqlResultConverter { // Delete the all elements that have already been grouped groupedElement.forEach((element) => { - mappingDefinitions.forEach((group) => { - delete element[group.objectToGroup]; + mappingDefinitions.forEach((mapDef) => { + delete element[mapDef.objectToGroup]; }); }); const nameToPush = { - [currGroup.name]: key, + [currentMappingDefition.name]: key, }; let objToPush = {}; if (!isEmpty(groupedElement[0])) { const groupToPush = { - [currGroup.childRoot]: groupedElement + [currentMappingDefition.childRoot]: groupedElement }; objToPush = { ...nameToPush, @@ -84,7 +81,7 @@ export class SparqlResultConverter { } - // Add the grouped element to the inputArray + // Add the grouped element to the outputArray outputArray.push(objToPush); }); @@ -94,7 +91,8 @@ export class SparqlResultConverter { interface MappingDefinition { - objectToGroup: string, - name: string, - childRoot: string + objectToGroup: string, + name: string, + childRoot: string, + toCollect?: string[]; } From 48be4d04f6af456600ddef7ee4c65fd32240947f Mon Sep 17 00:00:00 2001 From: Aljosha Koecher Date: Tue, 16 Jun 2020 17:19:40 +0200 Subject: [PATCH 09/16] Increased version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 97b42d5..6d1d271 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sparql-result-converter", - "version": "1.0.2", + "version": "1.0.3", "description": "Little utility function to that converts the table-like result of a SPARQL query into a JSON tree with a user-defined structure", "scripts": { "clean": "rimraf src", From 1e89b707a33d98eb3dcea486febd3afd2ee243bc Mon Sep 17 00:00:00 2001 From: Aljosha Koecher Date: Tue, 16 Jun 2020 17:22:16 +0200 Subject: [PATCH 10/16] Added some simple types --- src/ArrayUtil.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ArrayUtil.ts b/src/ArrayUtil.ts index 73ebb93..4e88bd1 100644 --- a/src/ArrayUtil.ts +++ b/src/ArrayUtil.ts @@ -5,7 +5,7 @@ export class ArrayUtil { * @param {*} arrayToCheck * @param {*} groupingProperty */ - static allEntriesContainGroupingProperty(arrayToCheck, groupingProperty) { + static allEntriesContainGroupingProperty(arrayToCheck: any[], groupingProperty: string): boolean { for (let i = 0; i < arrayToCheck.length; i++) { const element = arrayToCheck[i]; if (!Object.prototype.hasOwnProperty.call(element, groupingProperty)) { From 2efaa92a88156b7eb118f77463bbad7d748a8f41 Mon Sep 17 00:00:00 2001 From: Aljosha Koecher Date: Tue, 16 Jun 2020 18:12:24 +0200 Subject: [PATCH 11/16] Now building UMD modules, ignoring tests. Added separate build tsconfig --- tsconfig.build.json | 4 ++++ tsconfig.json | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 tsconfig.build.json diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 0000000..4eade54 --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["node_modules", "dist", "tests", "**/*test.ts"] +} diff --git a/tsconfig.json b/tsconfig.json index 3c9c192..aaa944e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,9 +5,9 @@ "declarationMap": true, "outDir": "./dist", "composite": true, - "rootDir": ".", + "rootDir": "./src", "baseUrl": "./", - "module": "CommonJS", + "module": "UMD", "target": "es2017", }, "exclude": ["dist", "node_modules"] From d2270fb9a4891cf57363f8d00177e8ca01b86235 Mon Sep 17 00:00:00 2001 From: Aljosha Koecher Date: Tue, 16 Jun 2020 18:12:50 +0200 Subject: [PATCH 12/16] Added build tsconfig, fixed falsely included files --- package.json | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 6d1d271..c9081b6 100644 --- a/package.json +++ b/package.json @@ -3,19 +3,18 @@ "version": "1.0.3", "description": "Little utility function to that converts the table-like result of a SPARQL query into a JSON tree with a user-defined structure", "scripts": { - "clean": "rimraf src", - "clean-node_modules": "rimraf node_modules", - "build": "tsc src", + "clean": "rimraf dist", + "build": "tsc --project tsconfig.build.json", "test": "npm run lint && npm run coverage", "test:only": "mocha -r ts-node/register tests/**/*.test.ts", "coverage": "nyc npm run test:only", - "lint": "eslint src tests/**/* --ext .ts" + "lint": "eslint src tests/**/* --ext .ts", + "prepublishOnly": "npm run lin && npm run coverage && npm run build" }, "files": [ - "lib", - "src" + "dist/**/*" ], - "main": "./lib/sparql-result-converter.js", + "main": "./dist/SparqlResultConverter.js", "repository": { "type": "git", "url": "git+https://github.com/aljoshakoecher/sparql-result-converter.git" From 592fd46f05d82ee17ff7ca78570181483d7cb86a Mon Sep 17 00:00:00 2001 From: Aljosha Koecher Date: Tue, 16 Jun 2020 18:13:27 +0200 Subject: [PATCH 13/16] Set return type to unknown as theres not much we can say about the return type --- src/SparqlResultConverter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SparqlResultConverter.ts b/src/SparqlResultConverter.ts index 3bd958a..8cd6c00 100644 --- a/src/SparqlResultConverter.ts +++ b/src/SparqlResultConverter.ts @@ -9,7 +9,7 @@ export class SparqlResultConverter { * @param {*} inputArray An array representing data structured as a table * @param {*} mappingDefinitions An array of objects representing the structure of the final output */ - convert(inputArray: SparqlResultLine[], mappingDefinitions: MappingDefinition[], currElement = 0): Record[] { + convert(inputArray: SparqlResultLine[], mappingDefinitions: MappingDefinition[], currElement = 0): unknown[] { let flattenedArray; // first: transform array From ef53ef700afae88f3a18ed4bcec2dcd4c8751f82 Mon Sep 17 00:00:00 2001 From: Aljosha Koecher Date: Tue, 16 Jun 2020 18:30:00 +0200 Subject: [PATCH 14/16] Updated documentation, added badges, fixed some typos --- README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c299098..16ffed3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,10 @@ +![npm](https://img.shields.io/npm/v/sparql-result-converter) +![GitHub](https://img.shields.io/github/license/aljoshakoecher/sparql-result-converter) + # sparql-result-converter A little utility class that helps you to transform the table-like results that you get from a SPARQL query into a nested JSON tree with a user-defined structure. -# How to use it +## How to use it Just install as a dependecy via `npm install sparql-result-converter`. In your code you can then use the converter like this: ```javascript @@ -10,11 +13,11 @@ const SparqlResultConverter = require('sparql-result-converter'); const converter = new SparqlResultConverter(); // convert a SPARQL result -const convertedResult = converter.convert(sparqlResult, convertStructure); +const convertedResult = converter.convert(inputArray, mappingDefinitions); ``` You have to pass two parameters to `convert()`: -1) `sparqlResult` are the results you get from your SPARQL query -2) `convertStructure` is an array that describes how your converted result should look like. It looks like this: +1) `inputArray` are the results you get from your SPARQL query +2) `mappingDefinitions` is an array that describes how your converted result should look like. It consists of mapping definitions looking like this: ```javascript const convertStructure = [ @@ -34,7 +37,7 @@ When you query Triple stores with their REST API, you get a tabular structure wh ![Example Graph](https://github.com/aljoshakoecher/sparql-result-converter/raw/documentation/images/docu-images/example-graph.png) -There are three pet owners with varying numbers of pets. While Peter has only one pet, mary has three. If we'd like to find all pet owners, their pets and the type of pet(s) they have, we migh send the following query against our triple store: +There are three pet owners with varying numbers of pets. While Peter has only one pet, mary has three. If we'd like to find all pet owners, their pets and the type of pet(s) they have, we might send the following query against our triple store: ```SPARQL PREFIX ex: PREFIX rdf: From 47661f618ef86d9ddb1d0444c77a81e959926ef5 Mon Sep 17 00:00:00 2001 From: Aljosha Koecher Date: Tue, 16 Jun 2020 18:34:33 +0200 Subject: [PATCH 15/16] Added tsconfig.buildinfo --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index d70577a..cda8e80 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ /out-tsc # Only exists if Bazel was run /bazel-out +tsconfig.build.tsbuildinfo +tsconfig.tsbuildinfo # Logs logs From 8745e4ad5cda0eb736d97fd22ce1c7a4f69df538 Mon Sep 17 00:00:00 2001 From: Aljosha Koecher Date: Tue, 16 Jun 2020 18:34:45 +0200 Subject: [PATCH 16/16] Fixed script type ("lin") --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c9081b6..7a199c7 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "test:only": "mocha -r ts-node/register tests/**/*.test.ts", "coverage": "nyc npm run test:only", "lint": "eslint src tests/**/* --ext .ts", - "prepublishOnly": "npm run lin && npm run coverage && npm run build" + "prepublishOnly": "npm run lint && npm run coverage && npm run build" }, "files": [ "dist/**/*"