feat: groupby nodule

This commit is contained in:
Joshua Shoemaker 2020-08-04 00:08:11 -05:00
parent 590f66f67d
commit 6d4f74679f
5 changed files with 198 additions and 2 deletions

View File

@ -225,6 +225,12 @@ Only the columns specified in the `structure` object will be exported from the `
export() // get the joined data from the Nodule export() // get the joined data from the Nodule
## GroupByNodule
The `GroupByNodule` class can take in `Table`s and a single value of `groupByValue` to group rows by a table header. On `export()` this will return an object with keys representing an array of objects (or `rows`)
The `asTable()` method is overloaded and actually returns an array of new `Table` instances, operating differently than the `Nodule` base class `asTable()`
## Constant Values ## Constant Values
A set of declared constant variables has been provided for safer typing. Although importing them is not essential, the values they represent are the only options for certain options. A set of declared constant variables has been provided for safer typing. Although importing them is not essential, the values they represent are the only options for certain options.

View File

@ -1,6 +1,6 @@
{ {
"name": "lovelacejs", "name": "lovelacejs",
"version": "0.1.6", "version": "0.2.0",
"description": "Lovelace.js is a modern JavaScript Library to create objects that easily mutate data through relationships, filtering, and tranforming the shape of data.", "description": "Lovelace.js is a modern JavaScript Library to create objects that easily mutate data through relationships, filtering, and tranforming the shape of data.",
"main": "index.js", "main": "index.js",
"directories": { "directories": {

View File

@ -0,0 +1,65 @@
import Nodule from '../Nodule.js'
import Table from '../Table.js'
class GroupByNodule extends Nodule {
constructor (props) {
super (props)
this._assignProps(props)
}
/* Overload the Nodule Method
Returns an Array of Tables with modified ids */
asTable = () => {
const exports = this.export()
const tables = []
for (let key in exports) {
const newTableProps = {
id: `${this.id}-${key}`,
label: `${this.label} by ${key}`,
rows: exports[key]
}
const table = new Table(newTableProps)
tables.push(table)
}
return tables
}
export = () => {
const { groupByValue } = this
const rows = this.tables.map(t => t.export() ).flat()
const groupedByRows = rows.reduce((groups, r) => {
const val = r[groupByValue]
groups[val] = groups[val] || []
groups[val].push(r)
return groups
}, {})
return groupedByRows
}
setGroupByValue = value => {
const valueValidation = this._validateGroupByValue(value)
if(valueValidation.status === 'ERR') throw valueValidation
else this.groupByValue = value
}
_assignProps = props => {
if (props.groupByValue) this.setGroupByValue(props.groupByValue)
}
_validateGroupByValue = value => {
const err = {
status: 'ERR',
error: {
label: 'Filter Parameter are not valid',
messages: []
}
}
if (typeof value !== 'string') {
const valueType = typeof value
err.error.messages.push(`GroupBy value was of type ${valueType}, should be a string`)
} else return { status: 'OK' }
}
}
export default GroupByNodule

View File

@ -0,0 +1,123 @@
import GroupByNodule from '../../../src/entities/nodules/GroupByNodule.js'
import Table from '../../../src/entities/Table.js'
const groupByTest = () => {
const expectedOutput = {
AshBritt: [
{ id: 'abc', data: 'row', contractor: 'AshBritt' },
{ id: 'qwe', data: 'lh', contractor: 'AshBritt' },
{ id: 'XYZ', data: 'row', contractor: 'AshBritt' }
],
HeyDay: [
{ id: 'XYZ', data: 'row', contractor: 'HeyDay' }
]
}
let table = {}
try {
table = new Table({
id: 'XYZ',
label: 'Test Table',
rows: [
{ id: 'abc', data: 'row', contractor: 'AshBritt' },
{ id: 'qwe', data: 'lh', contractor: 'AshBritt' },
{ id: 'XYZ', data: 'row', contractor: 'AshBritt' },
{ id: 'XYZ', data: 'row', contractor: 'HeyDay' },
]
})
} catch (err) {
return false
}
let groupByNodule = {}
try {
groupByNodule = new GroupByNodule({
id: 'ABC',
label: 'Test Group By',
tables: [table],
groupByValue: 'contractor'
})
} catch (err) {
console.log(err)
return false
}
const groupedRows = groupByNodule.export()
if (JSON.stringify(groupedRows) === JSON.stringify(expectedOutput)) {
return true
} else {
return false
}
}
const groupByAsTables = () => {
const expectedOutput = [
{
id: 'ABC-AshBritt',
label: 'Test Group by AshBritt',
rows: [
{ id: 'abc', data: 'row', contractor: 'AshBritt' },
{ id: 'qwe', data: 'lh', contractor: 'AshBritt' },
{ id: 'XYZ', data: 'row', contractor: 'AshBritt' }
],
headers: [ 'id', 'data', 'contractor' ],
type: 'Table',
isValid: true
},
{
id: 'ABC-HeyDay',
label: 'Test Group by HeyDay',
rows: [
{ id: 'XYZ', data: 'row', contractor: 'HeyDay' }
],
headers: [ 'id', 'data', 'contractor' ],
type: 'Table',
isValid: true
}
]
let table = {}
try {
table = new Table({
id: 'XYZ',
label: 'Test Table',
rows: [
{ id: 'abc', data: 'row', contractor: 'AshBritt' },
{ id: 'qwe', data: 'lh', contractor: 'AshBritt' },
{ id: 'XYZ', data: 'row', contractor: 'AshBritt' },
{ id: 'XYZ', data: 'row', contractor: 'HeyDay' },
]
})
} catch (err) {
return false
}
let groupByNodule = {}
try {
groupByNodule = new GroupByNodule({
id: 'ABC',
label: 'Test Group',
tables: [table],
groupByValue: 'contractor'
})
} catch (err) {
console.log(err)
return false
}
// make checks here
const groupedTables = groupByNodule.asTable()
const groupedTablesProps = groupedTables.map(t => t.getProperties())
if (JSON.stringify(groupedTablesProps) === JSON.stringify(expectedOutput)) {
return true
} else {
return false
}
}
export default [
{ name: 'Entity | GroupBy Value', test: groupByTest },
{ name: 'Entity | GroupBy As Table', test: groupByAsTables },
]

View File

@ -5,6 +5,7 @@ import noduleTests from '../tests/core/NoduleTests.js'
import filterNoduleTests from '../tests/core/nodules/filterNoduleTests.js' import filterNoduleTests from '../tests/core/nodules/filterNoduleTests.js'
import joinNoduleTests from '../tests/core/nodules/joinNoduleTests.js' import joinNoduleTests from '../tests/core/nodules/joinNoduleTests.js'
import transformNoduleTests from '../tests/core/nodules/transformNoduleTests.js' import transformNoduleTests from '../tests/core/nodules/transformNoduleTests.js'
import groupByNoduleTests from '../tests/core/nodules/groupByNoduleTests.js'
function runTestsAndReturnFailures (tests) { function runTestsAndReturnFailures (tests) {
const testTotalCount = tests.length const testTotalCount = tests.length
@ -34,7 +35,8 @@ const testsArray = [
noduleTests, noduleTests,
filterNoduleTests, filterNoduleTests,
joinNoduleTests, joinNoduleTests,
transformNoduleTests transformNoduleTests,
groupByNoduleTests
] ]
init (testsArray.flat()) init (testsArray.flat())