feat: groupby nodule
This commit is contained in:
parent
590f66f67d
commit
6d4f74679f
@ -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.
|
||||||
|
@ -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": {
|
||||||
|
65
src/entities/nodules/GroupByNodule.js
Normal file
65
src/entities/nodules/GroupByNodule.js
Normal 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
|
123
tests/core/nodules/groupByNoduleTests.js
Normal file
123
tests/core/nodules/groupByNoduleTests.js
Normal 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 },
|
||||||
|
]
|
@ -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())
|
Loading…
x
Reference in New Issue
Block a user