refact: convert to TS
This commit is contained in:
parent
2179a90562
commit
3939d560d0
@ -1,13 +0,0 @@
|
||||
{
|
||||
"presets": [
|
||||
"@babel/preset-env"
|
||||
],
|
||||
"plugins": [
|
||||
[
|
||||
"@babel/plugin-proposal-class-properties",
|
||||
{
|
||||
"loose": true
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
8
lib/constants/filterTypes.d.ts
vendored
Normal file
8
lib/constants/filterTypes.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
declare const filterTypes: {
|
||||
EQUAL: string;
|
||||
GREATER: string;
|
||||
GREATEREQUAL: string;
|
||||
LESSER: string;
|
||||
LESSEREQUAL: string;
|
||||
};
|
||||
export default filterTypes;
|
||||
10
lib/constants/filterTypes.js
Normal file
10
lib/constants/filterTypes.js
Normal file
@ -0,0 +1,10 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const filterTypes = {
|
||||
EQUAL: 'EQUAL',
|
||||
GREATER: 'GREATER',
|
||||
GREATEREQUAL: 'GREATEREQUAL',
|
||||
LESSER: 'LESSER',
|
||||
LESSEREQUAL: 'LESSEREQUAL',
|
||||
};
|
||||
exports.default = filterTypes;
|
||||
24
lib/entities/Nodule.d.ts
vendored
Normal file
24
lib/entities/Nodule.d.ts
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
import { noduleConstructorProps } from '../types/noduleTypes';
|
||||
import { tableProps, tableRows } from '../types/tableTypes';
|
||||
import Table from './Table';
|
||||
declare abstract class Nodule {
|
||||
id: string;
|
||||
label: string;
|
||||
type: 'Nodule';
|
||||
isValid: boolean;
|
||||
tables: Table[];
|
||||
constructor(props: noduleConstructorProps);
|
||||
abstract export(): tableRows;
|
||||
asTable: () => Table | null;
|
||||
getProperties: () => {
|
||||
id: string;
|
||||
label: string;
|
||||
type: "Nodule";
|
||||
tables: tableProps[];
|
||||
isValid: boolean;
|
||||
};
|
||||
setTables: (tablesToSet: Table[]) => void;
|
||||
private validateTables;
|
||||
private validateConstructionProps;
|
||||
}
|
||||
export default Nodule;
|
||||
120
lib/entities/Nodule.js
Normal file
120
lib/entities/Nodule.js
Normal file
@ -0,0 +1,120 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const Table_1 = require("./Table");
|
||||
class Nodule {
|
||||
id;
|
||||
label;
|
||||
type;
|
||||
isValid;
|
||||
tables = [];
|
||||
constructor(props) {
|
||||
const validatePropsResponse = this.validateConstructionProps(props);
|
||||
if (validatePropsResponse.status === 'ERR')
|
||||
throw validatePropsResponse;
|
||||
else {
|
||||
this.id = props.id;
|
||||
this.label = props.label;
|
||||
this.type = 'Nodule';
|
||||
this.isValid = true;
|
||||
if (props.tables)
|
||||
this.setTables(props.tables);
|
||||
}
|
||||
}
|
||||
asTable = () => {
|
||||
if (!this.export)
|
||||
return null;
|
||||
try {
|
||||
return new Table_1.default({
|
||||
id: this.id,
|
||||
label: this.label,
|
||||
rows: this.export()
|
||||
});
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
getProperties = () => {
|
||||
let tables = [];
|
||||
if (!Array.isArray(this.tables))
|
||||
tables = [];
|
||||
else if (this.tables.length === 0)
|
||||
tables = [];
|
||||
else
|
||||
tables = this.tables.map((t) => {
|
||||
return t.getProperties();
|
||||
});
|
||||
const properties = {
|
||||
id: this.id,
|
||||
label: this.label,
|
||||
type: this.type,
|
||||
tables: tables,
|
||||
isValid: this.isValid
|
||||
};
|
||||
return properties;
|
||||
};
|
||||
setTables = (tablesToSet) => {
|
||||
const validateTablesResponse = this.validateTables(tablesToSet);
|
||||
if (validateTablesResponse.status === 'ERR') {
|
||||
throw validateTablesResponse;
|
||||
}
|
||||
else {
|
||||
let tables = [];
|
||||
if (!Array.isArray(tablesToSet))
|
||||
tables = [tablesToSet];
|
||||
else
|
||||
tables = tablesToSet;
|
||||
this.tables = tables;
|
||||
}
|
||||
};
|
||||
validateTables = (tablesToImport) => {
|
||||
const err = {
|
||||
status: 'ERR',
|
||||
error: {
|
||||
label: 'Not all imported Tables are valid',
|
||||
messages: []
|
||||
}
|
||||
};
|
||||
let tables = [];
|
||||
if (!tablesToImport) {
|
||||
err.error.messages.push('No Tables imported');
|
||||
return err;
|
||||
}
|
||||
else if (!Array.isArray(tablesToImport)) {
|
||||
tables = [tablesToImport];
|
||||
}
|
||||
else
|
||||
tables = tablesToImport;
|
||||
for (let t = 0; t < tables.length; t++) {
|
||||
if (!tables[t].isValid) {
|
||||
err.error.messages.push(`Table[${t}] is not valid`);
|
||||
}
|
||||
}
|
||||
if (err.error.messages.length === 0) {
|
||||
return { status: 'OK' };
|
||||
}
|
||||
else {
|
||||
return err;
|
||||
}
|
||||
};
|
||||
validateConstructionProps = (props) => {
|
||||
const err = {
|
||||
status: 'ERR',
|
||||
error: {
|
||||
label: 'Error Creating Node',
|
||||
messages: []
|
||||
}
|
||||
};
|
||||
if (!props.id)
|
||||
err.error.messages.push('No id on creation of Node');
|
||||
if (!props.label)
|
||||
err.error.messages.push('No label on creation of Node');
|
||||
if (err.error.messages.length === 0) {
|
||||
return { status: 'OK' };
|
||||
}
|
||||
else {
|
||||
return err;
|
||||
}
|
||||
};
|
||||
}
|
||||
exports.default = Nodule;
|
||||
16
lib/entities/Table.d.ts
vendored
Normal file
16
lib/entities/Table.d.ts
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
import { tableConstructorProps, tableProps, tableRows } from "../types/tableTypes";
|
||||
declare class Table {
|
||||
id: string;
|
||||
label: string;
|
||||
rows: tableRows;
|
||||
type: 'Table';
|
||||
isValid: boolean;
|
||||
constructor(props: tableConstructorProps);
|
||||
getProperties: () => tableProps;
|
||||
get headers(): string[];
|
||||
export: () => tableRows;
|
||||
setRows: (rows: tableRows) => void;
|
||||
private validateConstructionProps;
|
||||
private validateRows;
|
||||
}
|
||||
export default Table;
|
||||
103
lib/entities/Table.js
Normal file
103
lib/entities/Table.js
Normal file
@ -0,0 +1,103 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
class Table {
|
||||
id;
|
||||
label;
|
||||
rows = [];
|
||||
type;
|
||||
isValid;
|
||||
constructor(props) {
|
||||
const validatePropsResponse = this.validateConstructionProps(props);
|
||||
if (validatePropsResponse.status === 'ERR')
|
||||
throw validatePropsResponse;
|
||||
else {
|
||||
this.id = props.id;
|
||||
this.label = props.label;
|
||||
this.type = 'Table';
|
||||
this.isValid = true;
|
||||
if (props.rows)
|
||||
this.setRows(props.rows);
|
||||
}
|
||||
}
|
||||
getProperties = () => {
|
||||
return {
|
||||
id: this.id,
|
||||
label: this.label,
|
||||
rows: this.rows,
|
||||
headers: this.headers,
|
||||
type: this.type,
|
||||
isValid: this.isValid
|
||||
};
|
||||
};
|
||||
get headers() {
|
||||
const rows = this.rows;
|
||||
if (!Array.isArray(rows) || rows.length < 1)
|
||||
return [];
|
||||
const length = rows.length;
|
||||
let lengthToSlice = 49;
|
||||
if (length < 50)
|
||||
lengthToSlice = length;
|
||||
const firstSliceOfRows = rows.slice(0, lengthToSlice);
|
||||
const headersOfSplicedRows = firstSliceOfRows.map(r => Object.keys(r));
|
||||
const flatenedHeaders = headersOfSplicedRows.flat();
|
||||
const uniqueHeaders = Array.from(new Set(flatenedHeaders));
|
||||
return uniqueHeaders;
|
||||
}
|
||||
export = () => this.rows;
|
||||
setRows = (rows) => {
|
||||
const rowsValidation = this.validateRows(rows);
|
||||
if (rowsValidation.status === 'ERR')
|
||||
throw rowsValidation;
|
||||
if (!Array.isArray(rows))
|
||||
this.rows = [rows];
|
||||
else
|
||||
this.rows = rows;
|
||||
};
|
||||
validateConstructionProps = (props) => {
|
||||
const err = {
|
||||
status: 'ERR',
|
||||
error: {
|
||||
label: 'Error Creating Table',
|
||||
messages: []
|
||||
}
|
||||
};
|
||||
if (!props) {
|
||||
err.error.messages.push('No props on creation of Table');
|
||||
return err;
|
||||
}
|
||||
if (!props.id)
|
||||
err.error.messages.push('No id on creation of Table');
|
||||
if (!props.label)
|
||||
err.error.messages.push('No label on creation of Table');
|
||||
if (err.error.messages.length === 0)
|
||||
return { status: 'OK' };
|
||||
else
|
||||
return err;
|
||||
};
|
||||
validateRows = (rowsToImport) => {
|
||||
const err = {
|
||||
status: 'ERR',
|
||||
error: {
|
||||
label: 'Error Creating Table',
|
||||
messages: []
|
||||
}
|
||||
};
|
||||
let rows = [];
|
||||
if (!Array.isArray(rowsToImport))
|
||||
rows = [rowsToImport];
|
||||
else
|
||||
rows = rowsToImport;
|
||||
if (rows.length === 0)
|
||||
err.error.messages.push('No Tables imported');
|
||||
for (let r = 0; r < rows.length; r++) {
|
||||
if (typeof rows[r] !== 'object') {
|
||||
err.error.messages.push(`row[${r}] is not an object`);
|
||||
}
|
||||
}
|
||||
if (err.error.messages.length > 0)
|
||||
return err;
|
||||
else
|
||||
return { status: 'OK' };
|
||||
};
|
||||
}
|
||||
exports.default = Table;
|
||||
14
lib/entities/nodules/FilterNodule.d.ts
vendored
Normal file
14
lib/entities/nodules/FilterNodule.d.ts
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
import Nodule from '../Nodule';
|
||||
import { filterNoduleConstructionProps, filterParams, filterType } from '../../types/noduleTypes';
|
||||
declare class FilterNodule extends Nodule {
|
||||
filterType?: filterType;
|
||||
filterParams: filterParams;
|
||||
constructor(props: filterNoduleConstructionProps);
|
||||
addFilter: (params: filterParams) => void;
|
||||
setFilterType: (filterType: filterType) => void;
|
||||
export: () => import("../../types/tableTypes").tableRow[];
|
||||
private createFilterMethods;
|
||||
private validateFilters;
|
||||
private validateType;
|
||||
}
|
||||
export default FilterNodule;
|
||||
93
lib/entities/nodules/FilterNodule.js
Normal file
93
lib/entities/nodules/FilterNodule.js
Normal file
@ -0,0 +1,93 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const Nodule_1 = require("../Nodule");
|
||||
const filterTypes_1 = require("../../constants/filterTypes");
|
||||
class FilterNodule extends Nodule_1.default {
|
||||
filterType;
|
||||
filterParams;
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.filterParams = props.filterParams;
|
||||
if (props.filterType)
|
||||
this.setFilterType(props.filterType);
|
||||
}
|
||||
addFilter = (params) => {
|
||||
const filterValidation = this.validateFilters(params);
|
||||
if (filterValidation.status === 'ERR')
|
||||
throw filterValidation;
|
||||
else
|
||||
this.filterParams = { ...this.filterParams, ...params };
|
||||
};
|
||||
setFilterType = (filterType) => {
|
||||
const typeValidation = this.validateType(filterType);
|
||||
if (typeValidation.status === 'ERR')
|
||||
throw typeValidation;
|
||||
else
|
||||
this.filterType = filterType;
|
||||
};
|
||||
export = () => {
|
||||
let rows = this.tables.map(t => t.export()).flat();
|
||||
let filters = this.createFilterMethods();
|
||||
filters.forEach((f) => {
|
||||
rows = rows.filter(f);
|
||||
});
|
||||
return rows;
|
||||
};
|
||||
createFilterMethods = () => {
|
||||
const typeValidation = this.validateType(this.filterType);
|
||||
if (typeValidation.status !== 'OK')
|
||||
throw typeValidation;
|
||||
let filters = [];
|
||||
for (let key in this.filterParams) {
|
||||
let filterMethod = () => { };
|
||||
if (this.filterType === filterTypes_1.default.EQUAL)
|
||||
filterMethod = (t) => t[key] === this.filterParams[key];
|
||||
else if (this.filterType === filterTypes_1.default.GREATER)
|
||||
filterMethod = (t) => t[key] > this.filterParams[key];
|
||||
else if (this.filterType === filterTypes_1.default.GREATEREQUAL)
|
||||
filterMethod = (t) => t[key] >= this.filterParams[key];
|
||||
else if (this.filterType === filterTypes_1.default.LESSER)
|
||||
filterMethod = (t) => t[key] < this.filterParams[key];
|
||||
else if (this.filterType === filterTypes_1.default.LESSEREQUAL)
|
||||
filterMethod = (t) => t[key] <= this.filterParams[key];
|
||||
filters.push(filterMethod);
|
||||
}
|
||||
return filters;
|
||||
};
|
||||
validateFilters = (params) => {
|
||||
const err = {
|
||||
status: 'ERR',
|
||||
error: {
|
||||
label: 'Filter Parameter are not valid',
|
||||
messages: []
|
||||
}
|
||||
};
|
||||
if (typeof params !== 'object') {
|
||||
const paramsType = typeof params;
|
||||
err.error.messages.push(`Filter was of type ${paramsType} should be an object`);
|
||||
}
|
||||
if (err.error.messages.length > 0)
|
||||
return err;
|
||||
else
|
||||
return { status: 'OK' };
|
||||
};
|
||||
validateType = (type) => {
|
||||
const err = {
|
||||
status: 'ERR',
|
||||
error: {
|
||||
label: 'Filter Type is not valid',
|
||||
messages: []
|
||||
}
|
||||
};
|
||||
if (!type)
|
||||
err.error.messages.push(`Type must be one of: ${Object.keys(filterTypes_1.default)}`);
|
||||
else if (Object.values(filterTypes_1.default).indexOf(type) < 0) {
|
||||
err.error.messages.push(`Type must be one of: ${Object.keys(filterTypes_1.default)}`);
|
||||
}
|
||||
if (err.error.messages.length > 0)
|
||||
return err;
|
||||
else
|
||||
return { status: 'OK' };
|
||||
};
|
||||
}
|
||||
exports.default = FilterNodule;
|
||||
14
lib/entities/nodules/GroupByNodule.d.ts
vendored
Normal file
14
lib/entities/nodules/GroupByNodule.d.ts
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
import { groupByNoduleConstructorProps, groupedByRows } from '../../types/noduleTypes';
|
||||
import Nodule from '../Nodule';
|
||||
import Table from '../Table';
|
||||
declare class GroupByNodule extends Nodule {
|
||||
groupByValue: string;
|
||||
constructor(props: groupByNoduleConstructorProps);
|
||||
asTables: () => Table[];
|
||||
asTable: () => never;
|
||||
export: () => never;
|
||||
exportTables: () => groupedByRows;
|
||||
setGroupByValue: (value: string) => void;
|
||||
private validateGroupByValue;
|
||||
}
|
||||
export default GroupByNodule;
|
||||
68
lib/entities/nodules/GroupByNodule.js
Normal file
68
lib/entities/nodules/GroupByNodule.js
Normal file
@ -0,0 +1,68 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const Nodule_1 = require("../Nodule");
|
||||
const Table_1 = require("../Table");
|
||||
class GroupByNodule extends Nodule_1.default {
|
||||
groupByValue = '';
|
||||
constructor(props) {
|
||||
super(props);
|
||||
if (props.groupByValue)
|
||||
this.setGroupByValue(props.groupByValue);
|
||||
}
|
||||
asTables = () => {
|
||||
const exports = this.exportTables();
|
||||
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_1.default(newTableProps);
|
||||
tables.push(table);
|
||||
}
|
||||
return tables;
|
||||
};
|
||||
asTable = () => {
|
||||
throw new Error('"asTable()" can not be called by GroupByNodule. Call "asTables()"');
|
||||
};
|
||||
export = () => {
|
||||
throw new Error('"export()" can not be called by GroupByNodule. Call "exportTables()"');
|
||||
};
|
||||
exportTables = () => {
|
||||
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;
|
||||
};
|
||||
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`);
|
||||
}
|
||||
if (err.error.messages.length > 0)
|
||||
return err;
|
||||
else
|
||||
return { status: 'OK' };
|
||||
};
|
||||
}
|
||||
exports.default = GroupByNodule;
|
||||
13
lib/entities/nodules/JoinNodule.d.ts
vendored
Normal file
13
lib/entities/nodules/JoinNodule.d.ts
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
import { joinBy, joinNoduleConstructionProps, joinParam } from '../../types/noduleTypes';
|
||||
import Nodule from '../Nodule';
|
||||
declare class JoinNodule extends Nodule {
|
||||
baseTableLabel: string;
|
||||
joinParams: joinParam[];
|
||||
constructor(props: joinNoduleConstructionProps);
|
||||
export: () => {
|
||||
[x: string]: unknown;
|
||||
}[];
|
||||
setJoinBy: (joinBy: joinBy) => void;
|
||||
private validateJoinBy;
|
||||
}
|
||||
export default JoinNodule;
|
||||
74
lib/entities/nodules/JoinNodule.js
Normal file
74
lib/entities/nodules/JoinNodule.js
Normal file
@ -0,0 +1,74 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const Nodule_1 = require("../Nodule");
|
||||
class JoinNodule extends Nodule_1.default {
|
||||
baseTableLabel = '';
|
||||
joinParams = [];
|
||||
constructor(props) {
|
||||
super(props);
|
||||
if (props.joinBy)
|
||||
this.setJoinBy(props.joinBy);
|
||||
}
|
||||
export = () => {
|
||||
const baseTable = this.tables.find(t => t.label === this.baseTableLabel);
|
||||
if (!baseTable)
|
||||
return [];
|
||||
const baseTableRows = baseTable.export();
|
||||
const tablesToJoin = this.tables.filter(t => {
|
||||
return t.label !== this.baseTableLabel;
|
||||
});
|
||||
const relatedTables = this.joinParams.map(joinParam => {
|
||||
const foreignTable = tablesToJoin.find(t => t.label === joinParam.foreignTable);
|
||||
if (!foreignTable)
|
||||
return [];
|
||||
const foreignTableRows = foreignTable.export();
|
||||
const mergedRows = baseTableRows.map(baseRow => {
|
||||
const matchingForeignRow = foreignTableRows.find(foreignRow => {
|
||||
return baseRow[joinParam.primaryTableKey] === foreignRow[joinParam.matchingKey];
|
||||
});
|
||||
let rowToMerge = {};
|
||||
for (let key in matchingForeignRow) {
|
||||
rowToMerge[`${joinParam.foreignTable}::${key}`] = matchingForeignRow[key];
|
||||
}
|
||||
return { ...baseRow, ...rowToMerge };
|
||||
});
|
||||
return mergedRows;
|
||||
});
|
||||
return relatedTables[0];
|
||||
};
|
||||
setJoinBy = (joinBy) => {
|
||||
const joinByValidation = this.validateJoinBy(joinBy);
|
||||
if (joinByValidation.status === 'ERR')
|
||||
throw joinByValidation;
|
||||
else {
|
||||
this.baseTableLabel = joinBy.baseTableLabel;
|
||||
this.joinParams = joinBy.joinParams;
|
||||
}
|
||||
};
|
||||
validateJoinBy = (joinBy) => {
|
||||
const err = {
|
||||
status: 'ERR',
|
||||
error: {
|
||||
label: 'JoinBy Parameters are not valid',
|
||||
messages: []
|
||||
}
|
||||
};
|
||||
const { baseTableLabel, joinParams } = joinBy;
|
||||
if (!baseTableLabel)
|
||||
err.error.messages.push('No baseTableLabel provided');
|
||||
if (!Array.isArray(joinParams)) {
|
||||
const joinParamsType = typeof joinParams;
|
||||
err.error.messages.push(`Keys was of type ${joinParamsType} should be an array`);
|
||||
return err;
|
||||
}
|
||||
for (let p = 0; p < joinParams.length; p++) {
|
||||
if (typeof joinParams[p] !== 'object')
|
||||
err.error.messages.push(`joinParams[${p}] is not an object`);
|
||||
}
|
||||
if (err.error.messages.length > 0)
|
||||
return err;
|
||||
else
|
||||
return { status: 'OK' };
|
||||
};
|
||||
}
|
||||
exports.default = JoinNodule;
|
||||
11
lib/entities/nodules/TransformNodule.d.ts
vendored
Normal file
11
lib/entities/nodules/TransformNodule.d.ts
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
import { transformNoduleConstructionProps, transformStruct } from '../../types/noduleTypes';
|
||||
import { tableRow } from '../../types/tableTypes';
|
||||
import Nodule from '../Nodule';
|
||||
declare class TransformNodule extends Nodule {
|
||||
structure: transformStruct;
|
||||
constructor(props: transformNoduleConstructionProps);
|
||||
export: () => tableRow[];
|
||||
setStructure: (struct: transformStruct) => void;
|
||||
private validateStructureProps;
|
||||
}
|
||||
export default TransformNodule;
|
||||
51
lib/entities/nodules/TransformNodule.js
Normal file
51
lib/entities/nodules/TransformNodule.js
Normal file
@ -0,0 +1,51 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const Nodule_1 = require("../Nodule");
|
||||
class TransformNodule extends Nodule_1.default {
|
||||
structure = {};
|
||||
constructor(props) {
|
||||
super(props);
|
||||
if (props.structure)
|
||||
this.setStructure(props.structure);
|
||||
}
|
||||
export = () => {
|
||||
const rows = this.tables.map(t => t.export()).flat();
|
||||
const transformedRows = rows.map(r => {
|
||||
let mapShape = {};
|
||||
for (const [key, value] of Object.entries(this.structure)) {
|
||||
mapShape[value] = r[key];
|
||||
}
|
||||
return mapShape;
|
||||
});
|
||||
return transformedRows;
|
||||
};
|
||||
setStructure = (struct) => {
|
||||
const structureValidation = this.validateStructureProps(struct);
|
||||
if (structureValidation.status === 'ERR')
|
||||
throw structureValidation;
|
||||
else
|
||||
this.structure = struct;
|
||||
};
|
||||
validateStructureProps = (struct) => {
|
||||
const err = {
|
||||
status: 'ERR',
|
||||
error: {
|
||||
label: 'Ptructure Parameters are not valid',
|
||||
messages: []
|
||||
}
|
||||
};
|
||||
if (!struct) {
|
||||
err.error.messages.push('No structure provided');
|
||||
return err;
|
||||
}
|
||||
for (let key in struct) {
|
||||
if (typeof struct[key] !== 'string')
|
||||
err.error.messages.push(`Key [${struct}] is not a String`);
|
||||
}
|
||||
if (err.error.messages.length > 0)
|
||||
return err;
|
||||
else
|
||||
return { status: 'OK' };
|
||||
};
|
||||
}
|
||||
exports.default = TransformNodule;
|
||||
16
lib/index.d.ts
vendored
Normal file
16
lib/index.d.ts
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
import Table from './entities/Table';
|
||||
import Nodule from './entities/Nodule';
|
||||
import FilterNodule from './entities/nodules/FilterNodule';
|
||||
import JoinNodule from './entities/nodules/JoinNodule.js';
|
||||
import TransformNodule from './entities/nodules/TransformNodule.js';
|
||||
import GroupByNodule from './entities/nodules/GroupByNodule.js';
|
||||
export { Table, Nodule, FilterNodule, JoinNodule, TransformNodule, GroupByNodule };
|
||||
declare const _default: {
|
||||
Table: typeof Table;
|
||||
Nodule: typeof Nodule;
|
||||
FilterNodule: typeof FilterNodule;
|
||||
JoinNodule: typeof JoinNodule;
|
||||
TransformNodule: typeof TransformNodule;
|
||||
GroupByNodule: typeof GroupByNodule;
|
||||
};
|
||||
export default _default;
|
||||
23
lib/index.js
Normal file
23
lib/index.js
Normal file
@ -0,0 +1,23 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.GroupByNodule = exports.TransformNodule = exports.JoinNodule = exports.FilterNodule = exports.Nodule = exports.Table = void 0;
|
||||
const Table_1 = require("./entities/Table");
|
||||
exports.Table = Table_1.default;
|
||||
const Nodule_1 = require("./entities/Nodule");
|
||||
exports.Nodule = Nodule_1.default;
|
||||
const FilterNodule_1 = require("./entities/nodules/FilterNodule");
|
||||
exports.FilterNodule = FilterNodule_1.default;
|
||||
const JoinNodule_js_1 = require("./entities/nodules/JoinNodule.js");
|
||||
exports.JoinNodule = JoinNodule_js_1.default;
|
||||
const TransformNodule_js_1 = require("./entities/nodules/TransformNodule.js");
|
||||
exports.TransformNodule = TransformNodule_js_1.default;
|
||||
const GroupByNodule_js_1 = require("./entities/nodules/GroupByNodule.js");
|
||||
exports.GroupByNodule = GroupByNodule_js_1.default;
|
||||
exports.default = {
|
||||
Table: Table_1.default,
|
||||
Nodule: Nodule_1.default,
|
||||
FilterNodule: FilterNodule_1.default,
|
||||
JoinNodule: JoinNodule_js_1.default,
|
||||
TransformNodule: TransformNodule_js_1.default,
|
||||
GroupByNodule: GroupByNodule_js_1.default
|
||||
};
|
||||
7
lib/types/errType.d.ts
vendored
Normal file
7
lib/types/errType.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
export declare type errType = {
|
||||
status: 'ERR' | 'OK';
|
||||
error: {
|
||||
label: string;
|
||||
messages: string[];
|
||||
};
|
||||
};
|
||||
2
lib/types/errType.js
Normal file
2
lib/types/errType.js
Normal file
@ -0,0 +1,2 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
36
lib/types/noduleTypes.d.ts
vendored
Normal file
36
lib/types/noduleTypes.d.ts
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
import Table from "../entities/Table";
|
||||
import { tableRow } from "./tableTypes";
|
||||
declare type noduleConstructorProps = {
|
||||
id: string;
|
||||
label: string;
|
||||
type?: 'Nodule';
|
||||
tables?: Table[];
|
||||
};
|
||||
declare type filterType = 'EQUAL' | 'GREATER' | 'GREATEREQUAL' | 'LESSER' | 'LESSEREQUAL';
|
||||
declare type filterParams = Record<string, string | number>;
|
||||
declare type filterNoduleConstructionProps = noduleConstructorProps & {
|
||||
filterType: filterType;
|
||||
} & {
|
||||
filterParams: filterParams;
|
||||
};
|
||||
declare type joinParam = {
|
||||
foreignTable: string;
|
||||
primaryTableKey: string;
|
||||
matchingKey: string;
|
||||
};
|
||||
declare type joinBy = {
|
||||
baseTableLabel: string;
|
||||
joinParams: joinParam[];
|
||||
};
|
||||
declare type joinNoduleConstructionProps = noduleConstructorProps & {
|
||||
joinBy: joinBy;
|
||||
};
|
||||
declare type transformStruct = Record<string, string>;
|
||||
declare type transformNoduleConstructionProps = noduleConstructorProps & {
|
||||
structure: transformStruct;
|
||||
};
|
||||
declare type groupByNoduleConstructorProps = noduleConstructorProps & {
|
||||
groupByValue: string;
|
||||
};
|
||||
declare type groupedByRows = Record<string, tableRow[]>;
|
||||
export { noduleConstructorProps, filterNoduleConstructionProps, filterType, filterParams, joinParam, joinBy, joinNoduleConstructionProps, transformStruct, transformNoduleConstructionProps, groupByNoduleConstructorProps, groupedByRows };
|
||||
2
lib/types/noduleTypes.js
Normal file
2
lib/types/noduleTypes.js
Normal file
@ -0,0 +1,2 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
17
lib/types/tableTypes.d.ts
vendored
Normal file
17
lib/types/tableTypes.d.ts
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
declare type tableConstructorProps = {
|
||||
id: string;
|
||||
label: string;
|
||||
rows: tableRows;
|
||||
type?: 'Table';
|
||||
};
|
||||
declare type tableRow = Record<string, unknown>;
|
||||
declare type tableRows = tableRow[];
|
||||
declare type tableProps = {
|
||||
id: string;
|
||||
label: string;
|
||||
rows: tableRows;
|
||||
headers: string[];
|
||||
type: 'Table';
|
||||
isValid: boolean;
|
||||
};
|
||||
export { tableConstructorProps, tableRow, tableRows, tableProps };
|
||||
2
lib/types/tableTypes.js
Normal file
2
lib/types/tableTypes.js
Normal file
@ -0,0 +1,2 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
13080
package-lock.json
generated
Normal file
13080
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
@ -1,14 +1,15 @@
|
||||
{
|
||||
"name": "lovelacejs",
|
||||
"version": "0.2.1",
|
||||
"version": "0.2.2",
|
||||
"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",
|
||||
"directories": {
|
||||
"test": "tests"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "webpack --mode production",
|
||||
"tests": "node ./tests/index.js"
|
||||
"build": "tsc",
|
||||
"lint": "tslint -p tsconfig.json",
|
||||
"tests": "ts-node ./tests/index.ts"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -25,6 +26,9 @@
|
||||
"@babel/plugin-proposal-class-properties": "^7.10.1",
|
||||
"@babel/preset-env": "^7.10.3",
|
||||
"babel-loader": "^8.1.0",
|
||||
"ts-node": "^10.8.1",
|
||||
"tslint": "^6.1.3",
|
||||
"typescript": "^4.7.4",
|
||||
"webpack": "^4.43.0",
|
||||
"webpack-cli": "^3.3.12"
|
||||
}
|
||||
|
||||
@ -1,16 +1,30 @@
|
||||
import Table from './Table.js'
|
||||
import { errType } from '../types/errType'
|
||||
import { noduleConstructorProps } from '../types/noduleTypes'
|
||||
import { tableProps, tableRows } from '../types/tableTypes'
|
||||
import Table from './Table'
|
||||
|
||||
class Nodule {
|
||||
constructor (props) {
|
||||
const validatePropsResponse = this._validateConstructionProps(props)
|
||||
if (validatePropsResponse.status === 'ERR') {
|
||||
throw validatePropsResponse
|
||||
}
|
||||
abstract class Nodule {
|
||||
id: string
|
||||
label: string
|
||||
type: 'Nodule'
|
||||
isValid: boolean
|
||||
tables: Table[] = []
|
||||
|
||||
constructor (props: noduleConstructorProps) {
|
||||
const validatePropsResponse = this.validateConstructionProps(props)
|
||||
if (validatePropsResponse.status === 'ERR') throw validatePropsResponse
|
||||
else {
|
||||
this._assignProps(props)
|
||||
this.id = props.id
|
||||
this.label = props.label
|
||||
this.type = 'Nodule'
|
||||
this.isValid = true
|
||||
|
||||
if (props.tables) this.setTables(props.tables)
|
||||
}
|
||||
}
|
||||
|
||||
abstract export () : tableRows
|
||||
|
||||
asTable = () => {
|
||||
if (!this.export) return null
|
||||
try {
|
||||
@ -25,10 +39,10 @@ class Nodule {
|
||||
}
|
||||
|
||||
getProperties = () => {
|
||||
let tables = []
|
||||
let tables: tableProps[] = []
|
||||
if (!Array.isArray(this.tables)) tables = []
|
||||
else if (this.tables.length === 0) tables = []
|
||||
else tables = this.tables.map(t => {
|
||||
else tables = this.tables.map((t: Table) => {
|
||||
return t.getProperties()
|
||||
})
|
||||
|
||||
@ -43,35 +57,20 @@ class Nodule {
|
||||
return properties
|
||||
}
|
||||
|
||||
importTables = tablesToImport => {
|
||||
console.log('Function importTables has been depricated, please use "setTables()"')
|
||||
this.setTables(tablesToImport)
|
||||
}
|
||||
|
||||
setTables = tablesToSet => {
|
||||
const validateTablesResponse = this._validateTables(tablesToSet)
|
||||
setTables = (tablesToSet: Table[]) => {
|
||||
const validateTablesResponse = this.validateTables(tablesToSet)
|
||||
if (validateTablesResponse.status === 'ERR') {
|
||||
throw validateTablesResponse
|
||||
} else {
|
||||
let tables = []
|
||||
let tables: Table[] = []
|
||||
if (!Array.isArray(tablesToSet)) tables = [tablesToSet]
|
||||
else tables = tablesToSet
|
||||
this.tables = tables
|
||||
}
|
||||
}
|
||||
|
||||
_assignProps = props => {
|
||||
this.id = props.id
|
||||
this.label = props.label
|
||||
this.type = 'Nodule'
|
||||
this.isValid = true
|
||||
|
||||
if (props.tables) this.setTables(props.tables)
|
||||
else this.tables = []
|
||||
}
|
||||
|
||||
_validateTables = tablesToImport => {
|
||||
const err = {
|
||||
private validateTables = (tablesToImport: Table[]) => {
|
||||
const err: errType = {
|
||||
status: 'ERR',
|
||||
error: {
|
||||
label: 'Not all imported Tables are valid',
|
||||
@ -100,8 +99,8 @@ class Nodule {
|
||||
}
|
||||
}
|
||||
|
||||
_validateConstructionProps = (props) => {
|
||||
const err = {
|
||||
private validateConstructionProps = (props: noduleConstructorProps) => {
|
||||
const err: errType = {
|
||||
status: 'ERR',
|
||||
error: {
|
||||
label: 'Error Creating Node',
|
||||
@ -1,11 +1,27 @@
|
||||
import { errType } from "../types/errType"
|
||||
import { tableConstructorProps, tableProps, tableRows } from "../types/tableTypes"
|
||||
|
||||
class Table {
|
||||
constructor (props) {
|
||||
const validatePropsResponse = this._validateConstructionProps(props)
|
||||
id: string
|
||||
label: string
|
||||
rows: tableRows = []
|
||||
type: 'Table'
|
||||
isValid: boolean
|
||||
|
||||
constructor (props: tableConstructorProps) {
|
||||
const validatePropsResponse = this.validateConstructionProps(props)
|
||||
if (validatePropsResponse.status === 'ERR') throw validatePropsResponse
|
||||
else this._assignProps(props)
|
||||
else {
|
||||
this.id = props.id
|
||||
this.label = props.label
|
||||
this.type = 'Table'
|
||||
this.isValid = true
|
||||
|
||||
if (props.rows) this.setRows(props.rows)
|
||||
}
|
||||
}
|
||||
|
||||
getProperties = () => {
|
||||
getProperties = (): tableProps => {
|
||||
return {
|
||||
id: this.id,
|
||||
label: this.label,
|
||||
@ -33,26 +49,16 @@ class Table {
|
||||
|
||||
export = () => this.rows
|
||||
|
||||
setRows = rows => {
|
||||
const rowsValidation = this._validateRows(rows)
|
||||
setRows = (rows: tableRows) => {
|
||||
const rowsValidation = this.validateRows(rows)
|
||||
if (rowsValidation.status === 'ERR') throw rowsValidation
|
||||
|
||||
if (!Array.isArray(rows)) this.rows = [rows]
|
||||
else this.rows = rows
|
||||
}
|
||||
|
||||
_assignProps = props => {
|
||||
this.id = props.id
|
||||
this.label = props.label
|
||||
this.type = 'Table'
|
||||
this.isValid = true
|
||||
|
||||
if (props.rows) this.setRows(props.rows)
|
||||
else this.rows = []
|
||||
}
|
||||
|
||||
_validateConstructionProps = props => {
|
||||
const err = {
|
||||
private validateConstructionProps = (props: tableConstructorProps) => {
|
||||
const err: errType = {
|
||||
status: 'ERR',
|
||||
error: {
|
||||
label: 'Error Creating Table',
|
||||
@ -71,8 +77,8 @@ class Table {
|
||||
else return err
|
||||
}
|
||||
|
||||
_validateRows = rowsToImport => {
|
||||
const err = {
|
||||
private validateRows = (rowsToImport: tableRows) => {
|
||||
const err: errType = {
|
||||
status: 'ERR',
|
||||
error: {
|
||||
label: 'Error Creating Table',
|
||||
@ -1,65 +1,67 @@
|
||||
import Nodule from '../Nodule.js'
|
||||
import filterTypes from '../../constants/filterTypes.js'
|
||||
import Nodule from '../Nodule'
|
||||
import filterTypes from '../../constants/filterTypes'
|
||||
import { filterNoduleConstructionProps, filterParams, filterType } from '../../types/noduleTypes'
|
||||
import { errType } from '../../types/errType'
|
||||
|
||||
class FilterNodule extends Nodule {
|
||||
constructor (props) {
|
||||
filterType?: filterType
|
||||
filterParams: filterParams
|
||||
|
||||
constructor (props: filterNoduleConstructionProps) {
|
||||
super (props)
|
||||
this._assignProps(props)
|
||||
|
||||
this.filterParams = props.filterParams
|
||||
if (props.filterType) this.setFilterType(props.filterType)
|
||||
}
|
||||
|
||||
addFilter = params => {
|
||||
const filterValidation = this._validateFilters(params)
|
||||
addFilter = (params: filterParams) => {
|
||||
const filterValidation = this.validateFilters(params)
|
||||
if (filterValidation.status === 'ERR') throw filterValidation
|
||||
else this.filterParams = {...this.filterParams, ...params}
|
||||
}
|
||||
|
||||
setFilterType = filterType => {
|
||||
const typeValidation = this._validateType(filterType)
|
||||
setFilterType = (filterType: filterType) => {
|
||||
const typeValidation = this.validateType(filterType)
|
||||
if (typeValidation.status === 'ERR') throw typeValidation
|
||||
else this.filterType = filterType
|
||||
}
|
||||
|
||||
export = () => {
|
||||
let rows = this.tables.map(t => t.export() ).flat()
|
||||
let filters = this._createFilterMethods()
|
||||
let filters = this.createFilterMethods()
|
||||
|
||||
filters.forEach(f => {
|
||||
filters.forEach((f: any) => { // TODO: I dont like the any, gotta find a type solution
|
||||
rows = rows.filter(f)
|
||||
})
|
||||
|
||||
return rows
|
||||
}
|
||||
|
||||
_assignProps = props => {
|
||||
this.filterParams = props.filterParams || {}
|
||||
if (props.filterType) this.setFilterType(props.filterType)
|
||||
}
|
||||
|
||||
_createFilterMethods = () => {
|
||||
const typeValidation = this._validateType(this.filterType)
|
||||
private createFilterMethods = (): Function[] => {
|
||||
const typeValidation = this.validateType(this.filterType)
|
||||
if (typeValidation.status !== 'OK') throw typeValidation
|
||||
|
||||
let filters = []
|
||||
let filters: Function[] = []
|
||||
for (let key in this.filterParams) {
|
||||
let filterMethod = {}
|
||||
let filterMethod: Function = () => {}
|
||||
if (this.filterType === filterTypes.EQUAL)
|
||||
filterMethod = t => t[key] === this.filterParams[key]
|
||||
filterMethod = (t: filterParams) => t[key] === this.filterParams[key]
|
||||
else if (this.filterType === filterTypes.GREATER)
|
||||
filterMethod = t => t[key] > this.filterParams[key]
|
||||
filterMethod = (t: filterParams) => t[key] > this.filterParams[key]
|
||||
else if (this.filterType === filterTypes.GREATEREQUAL)
|
||||
filterMethod = t => t[key] >= this.filterParams[key]
|
||||
filterMethod = (t: filterParams) => t[key] >= this.filterParams[key]
|
||||
else if (this.filterType === filterTypes.LESSER)
|
||||
filterMethod = t => t[key] < this.filterParams[key]
|
||||
filterMethod = (t: filterParams) => t[key] < this.filterParams[key]
|
||||
else if (this.filterType === filterTypes.LESSEREQUAL)
|
||||
filterMethod = t => t[key] <= this.filterParams[key]
|
||||
filterMethod = (t: filterParams) => t[key] <= this.filterParams[key]
|
||||
|
||||
filters.push(filterMethod)
|
||||
}
|
||||
return filters
|
||||
}
|
||||
|
||||
_validateFilters = params => {
|
||||
const err = {
|
||||
private validateFilters = (params: filterParams) => {
|
||||
const err: errType = {
|
||||
status: 'ERR',
|
||||
error: {
|
||||
label: 'Filter Parameter are not valid',
|
||||
@ -76,8 +78,8 @@ class FilterNodule extends Nodule {
|
||||
else return { status: 'OK' }
|
||||
}
|
||||
|
||||
_validateType = type => {
|
||||
const err = {
|
||||
private validateType = (type?: filterType) => {
|
||||
const err: errType = {
|
||||
status: 'ERR',
|
||||
error: {
|
||||
label: 'Filter Type is not valid',
|
||||
@ -85,7 +87,8 @@ class FilterNodule extends Nodule {
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.values(filterTypes).indexOf(type) < 0) {
|
||||
if(!type) err.error.messages.push(`Type must be one of: ${Object.keys(filterTypes)}`)
|
||||
else if (Object.values(filterTypes).indexOf(type) < 0) {
|
||||
err.error.messages.push(`Type must be one of: ${Object.keys(filterTypes)}`)
|
||||
}
|
||||
|
||||
@ -1,65 +0,0 @@
|
||||
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
|
||||
75
src/entities/nodules/GroupByNodule.ts
Normal file
75
src/entities/nodules/GroupByNodule.ts
Normal file
@ -0,0 +1,75 @@
|
||||
import { errType } from '../../types/errType'
|
||||
import { groupByNoduleConstructorProps, groupedByRows } from '../../types/noduleTypes'
|
||||
import { tableConstructorProps } from '../../types/tableTypes'
|
||||
import Nodule from '../Nodule'
|
||||
import Table from '../Table'
|
||||
|
||||
class GroupByNodule extends Nodule {
|
||||
groupByValue: string = ''
|
||||
|
||||
constructor (props: groupByNoduleConstructorProps) {
|
||||
super (props)
|
||||
if (props.groupByValue) this.setGroupByValue(props.groupByValue)
|
||||
}
|
||||
|
||||
asTables = (): Table[] => {
|
||||
const exports = this.exportTables()
|
||||
const tables = []
|
||||
for (let key in exports) {
|
||||
const newTableProps: tableConstructorProps = {
|
||||
id: `${this.id}-${key}`,
|
||||
label: `${this.label} by ${key}`,
|
||||
rows: exports[key]
|
||||
}
|
||||
const table = new Table(newTableProps)
|
||||
tables.push(table)
|
||||
}
|
||||
return tables
|
||||
}
|
||||
|
||||
asTable = () => {
|
||||
throw new Error('"asTable()" can not be called by GroupByNodule. Call "asTables()"')
|
||||
}
|
||||
|
||||
export = () => {
|
||||
throw new Error('"export()" can not be called by GroupByNodule. Call "exportTables()"')
|
||||
}
|
||||
|
||||
exportTables = (): groupedByRows => {
|
||||
const { groupByValue } = this
|
||||
const rows = this.tables.map(t => t.export() ).flat()
|
||||
const groupedByRows = rows.reduce((groups: groupedByRows, r) => {
|
||||
const val: string = r[groupByValue] as string
|
||||
groups[val] = groups[val] || []
|
||||
groups[val].push(r)
|
||||
return groups
|
||||
}, {})
|
||||
return groupedByRows
|
||||
}
|
||||
|
||||
setGroupByValue = (value: string) => {
|
||||
const valueValidation = this.validateGroupByValue(value)
|
||||
if(valueValidation.status === 'ERR') throw valueValidation
|
||||
else this.groupByValue = value
|
||||
}
|
||||
|
||||
private validateGroupByValue = (value: string) => {
|
||||
const err: errType = {
|
||||
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`)
|
||||
}
|
||||
|
||||
if (err.error.messages.length > 0) return err
|
||||
else return { status: 'OK' }
|
||||
}
|
||||
}
|
||||
|
||||
export default GroupByNodule
|
||||
@ -1,29 +1,37 @@
|
||||
import Nodule from '../Nodule.js'
|
||||
import { errType } from '../../types/errType'
|
||||
import { joinBy, joinNoduleConstructionProps, joinParam } from '../../types/noduleTypes'
|
||||
import { tableRow } from '../../types/tableTypes'
|
||||
import Nodule from '../Nodule'
|
||||
|
||||
class JoinNodule extends Nodule {
|
||||
constructor (props) {
|
||||
baseTableLabel: string = ''
|
||||
joinParams: joinParam[] = []
|
||||
|
||||
constructor (props: joinNoduleConstructionProps) {
|
||||
super(props)
|
||||
this._assignProps(props)
|
||||
if (props.joinBy) this.setJoinBy(props.joinBy)
|
||||
}
|
||||
|
||||
export = () => {
|
||||
const baseTable = this.tables.find(t => t.label === this.baseTableLabel)
|
||||
if (!baseTable) return []
|
||||
|
||||
const baseTableRows = baseTable.export()
|
||||
const tablesToJoin = this.tables.filter(t => {
|
||||
return t.label !== this.baseTableLabel
|
||||
})
|
||||
|
||||
const relatedTables = this.joinParams.map(joinParam => {
|
||||
const foreignTable = tablesToJoin.find(t => {
|
||||
return t.label === joinParam.foreignTable
|
||||
})
|
||||
const foreignTable = tablesToJoin.find(t => t.label === joinParam.foreignTable)
|
||||
if (!foreignTable) return []
|
||||
|
||||
const foreignTableRows = foreignTable.export()
|
||||
|
||||
const mergedRows = baseTableRows.map(baseRow => {
|
||||
const matchingForeignRow = foreignTableRows.find(foreignRow => {
|
||||
return baseRow[joinParam.primaryTableKey] === foreignRow[joinParam.matchingKey]
|
||||
})
|
||||
let rowToMerge = {}
|
||||
let rowToMerge: tableRow = {}
|
||||
for (let key in matchingForeignRow) {
|
||||
rowToMerge[`${joinParam.foreignTable}::${key}`] = matchingForeignRow[key]
|
||||
}
|
||||
@ -36,8 +44,8 @@ class JoinNodule extends Nodule {
|
||||
return relatedTables[0]
|
||||
}
|
||||
|
||||
setJoinBy = joinBy => {
|
||||
const joinByValidation = this._validateJoinBy(joinBy)
|
||||
setJoinBy = (joinBy: joinBy) => {
|
||||
const joinByValidation = this.validateJoinBy(joinBy)
|
||||
if (joinByValidation.status === 'ERR') throw joinByValidation
|
||||
else {
|
||||
this.baseTableLabel = joinBy.baseTableLabel
|
||||
@ -45,12 +53,8 @@ class JoinNodule extends Nodule {
|
||||
}
|
||||
}
|
||||
|
||||
_assignProps = props => {
|
||||
if (props.joinBy) this.setJoinBy(props.joinBy)
|
||||
}
|
||||
|
||||
_validateJoinBy = joinBy => {
|
||||
const err = {
|
||||
private validateJoinBy = (joinBy: joinBy) => {
|
||||
const err: errType = {
|
||||
status: 'ERR',
|
||||
error: {
|
||||
label: 'JoinBy Parameters are not valid',
|
||||
@ -1,16 +1,21 @@
|
||||
import Nodule from '../Nodule.js'
|
||||
import { errType } from '../../types/errType'
|
||||
import { transformNoduleConstructionProps, transformStruct } from '../../types/noduleTypes'
|
||||
import { tableRow } from '../../types/tableTypes'
|
||||
import Nodule from '../Nodule'
|
||||
|
||||
class TransformNodule extends Nodule {
|
||||
constructor (props) {
|
||||
structure: transformStruct = {}
|
||||
|
||||
constructor (props: transformNoduleConstructionProps) {
|
||||
super(props)
|
||||
this._assignProps(props)
|
||||
if (props.structure) this.setStructure(props.structure)
|
||||
}
|
||||
|
||||
export = () => {
|
||||
const rows = this.tables.map(t => t.export()).flat()
|
||||
|
||||
const transformedRows = rows.map(r => {
|
||||
let mapShape = {}
|
||||
let mapShape: tableRow = {}
|
||||
for (const [ key, value ] of Object.entries(this.structure)) {
|
||||
mapShape[value] = r[key]
|
||||
}
|
||||
@ -19,18 +24,14 @@ class TransformNodule extends Nodule {
|
||||
return transformedRows
|
||||
}
|
||||
|
||||
setStructure = struct => {
|
||||
const structureValidation = this._validateStructureProps(struct)
|
||||
setStructure = (struct: transformStruct) => {
|
||||
const structureValidation = this.validateStructureProps(struct)
|
||||
if (structureValidation.status === 'ERR') throw structureValidation
|
||||
else this.structure = struct
|
||||
}
|
||||
|
||||
_assignProps = props => {
|
||||
if (props.structure) this.setStructure(props.structure)
|
||||
}
|
||||
|
||||
_validateStructureProps = struct => {
|
||||
const err = {
|
||||
private validateStructureProps = (struct: transformStruct) => {
|
||||
const err: errType = {
|
||||
status: 'ERR',
|
||||
error: {
|
||||
label: 'Ptructure Parameters are not valid',
|
||||
@ -1,6 +1,6 @@
|
||||
import Table from './entities/Table.js'
|
||||
import Nodule from './entities/Nodule.js'
|
||||
import FilterNodule from './entities/nodules/FilterNodule.js'
|
||||
import Table from './entities/Table'
|
||||
import Nodule from './entities/Nodule'
|
||||
import FilterNodule from './entities/nodules/FilterNodule'
|
||||
import JoinNodule from './entities/nodules/JoinNodule.js'
|
||||
import TransformNodule from './entities/nodules/TransformNodule.js'
|
||||
import GroupByNodule from './entities/nodules/GroupByNodule.js'
|
||||
7
src/types/errType.ts
Normal file
7
src/types/errType.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export type errType = {
|
||||
status: 'ERR' | 'OK',
|
||||
error: {
|
||||
label: string,
|
||||
messages: string[]
|
||||
}
|
||||
}
|
||||
38
src/types/noduleTypes.ts
Normal file
38
src/types/noduleTypes.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import Table from "../entities/Table"
|
||||
import { tableRow } from "./tableTypes"
|
||||
|
||||
type noduleConstructorProps = {
|
||||
id: string,
|
||||
label: string,
|
||||
type?: 'Nodule'
|
||||
tables?: Table[]
|
||||
}
|
||||
|
||||
type filterType = 'EQUAL' | 'GREATER' | 'GREATEREQUAL' | 'LESSER' | 'LESSEREQUAL'
|
||||
type filterParams = Record<string, string | number>
|
||||
type filterNoduleConstructionProps = noduleConstructorProps & {filterType: filterType} & {filterParams: filterParams}
|
||||
|
||||
type joinParam = { foreignTable: string, primaryTableKey: string, matchingKey: string }
|
||||
type joinBy = { baseTableLabel: string, joinParams: joinParam[] }
|
||||
type joinNoduleConstructionProps = noduleConstructorProps & { joinBy: joinBy }
|
||||
|
||||
type transformStruct = Record<string, string>
|
||||
type transformNoduleConstructionProps = noduleConstructorProps & { structure: transformStruct }
|
||||
|
||||
type groupByNoduleConstructorProps = noduleConstructorProps & { groupByValue: string }
|
||||
|
||||
type groupedByRows = Record<string, tableRow[]>
|
||||
|
||||
export {
|
||||
noduleConstructorProps,
|
||||
filterNoduleConstructionProps,
|
||||
filterType,
|
||||
filterParams,
|
||||
joinParam,
|
||||
joinBy,
|
||||
joinNoduleConstructionProps,
|
||||
transformStruct,
|
||||
transformNoduleConstructionProps,
|
||||
groupByNoduleConstructorProps,
|
||||
groupedByRows
|
||||
}
|
||||
26
src/types/tableTypes.ts
Normal file
26
src/types/tableTypes.ts
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
type tableConstructorProps = {
|
||||
id: string,
|
||||
label: string,
|
||||
rows: tableRows,
|
||||
type?: 'Table',
|
||||
}
|
||||
|
||||
type tableRow = Record<string, unknown>
|
||||
type tableRows = tableRow[]
|
||||
|
||||
type tableProps = {
|
||||
id: string,
|
||||
label: string,
|
||||
rows: tableRows,
|
||||
headers: string[],
|
||||
type: 'Table',
|
||||
isValid: boolean
|
||||
}
|
||||
|
||||
export {
|
||||
tableConstructorProps,
|
||||
tableRow,
|
||||
tableRows,
|
||||
tableProps
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
import Nodule from '../../src/entities/Nodule.js'
|
||||
import Table from '../../src/entities/Table.js'
|
||||
import Nodule from '../../src/entities/Nodule'
|
||||
import Table from '../../src/entities/Table'
|
||||
|
||||
const input = {
|
||||
id: 'ABC',
|
||||
@ -65,44 +65,6 @@ const createNodeWithoutTables = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const importTables = () => {
|
||||
const table = new Table({
|
||||
id: 'XYZ',
|
||||
label: 'Test Table',
|
||||
rows: [{ id: 'abc', data: 'row' }]
|
||||
})
|
||||
|
||||
const expectedOutput = {
|
||||
id: 'ABC',
|
||||
label: 'Test Node',
|
||||
type: 'Nodule',
|
||||
tables: [{
|
||||
id: 'XYZ',
|
||||
label: 'Test Table',
|
||||
rows: [{ id: 'abc', data: 'row' }],
|
||||
headers: [ 'id', 'data' ],
|
||||
type: 'Table',
|
||||
isValid: true
|
||||
}],
|
||||
isValid: true
|
||||
}
|
||||
|
||||
try {
|
||||
const nodule = new Nodule({
|
||||
id: 'ABC',
|
||||
label: 'Test Node',
|
||||
})
|
||||
nodule.importTables(table)
|
||||
const nodeProps = nodule.getProperties()
|
||||
|
||||
if (JSON.stringify(nodeProps) == JSON.stringify(expectedOutput)) return true
|
||||
else return false
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const failToExport = () => {
|
||||
const expectedOutput = null
|
||||
const nodule = new Nodule({
|
||||
@ -163,7 +125,6 @@ const setTables = () => {
|
||||
export default [
|
||||
{ name: 'Entity | Get Nodule Properties', test: getNodeProperties },
|
||||
{ name: 'Entity | Create Nodule Without Tables', test: createNodeWithoutTables },
|
||||
{ name: 'Entity | Import Tables to Nodule', test: importTables },
|
||||
{ name: 'Entity | Fail to Export', test: failToExport },
|
||||
{ name: 'Entity | Nodule setTables', test: setTables }
|
||||
]
|
||||
@ -1,5 +1,5 @@
|
||||
import FilterNodule from '../../../src/entities/nodules/FilterNodule.js'
|
||||
import Table from '../../../src/entities/Table.js'
|
||||
import FilterNodule from '../../../src/entities/nodules/FilterNodule'
|
||||
import Table from '../../../src/entities/Table'
|
||||
|
||||
const equalFilter = () => {
|
||||
const expectedOutput = [
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import GroupByNodule from '../../../src/entities/nodules/GroupByNodule.js'
|
||||
import Table from '../../../src/entities/Table.js'
|
||||
import GroupByNodule from '../../../src/entities/nodules/GroupByNodule'
|
||||
import Table from '../../../src/entities/Table'
|
||||
|
||||
const groupByTest = () => {
|
||||
const expectedOutput = {
|
||||
@ -42,7 +42,7 @@ const groupByTest = () => {
|
||||
return false
|
||||
}
|
||||
|
||||
const groupedRows = groupByNodule.export()
|
||||
const groupedRows = groupByNodule.exportTables()
|
||||
if (JSON.stringify(groupedRows) === JSON.stringify(expectedOutput)) {
|
||||
return true
|
||||
} else {
|
||||
@ -107,7 +107,7 @@ const groupByAsTables = () => {
|
||||
}
|
||||
|
||||
// make checks here
|
||||
const groupedTables = groupByNodule.asTable()
|
||||
const groupedTables = groupByNodule.asTables()
|
||||
const groupedTablesProps = groupedTables.map(t => t.getProperties())
|
||||
if (JSON.stringify(groupedTablesProps) === JSON.stringify(expectedOutput)) {
|
||||
return true
|
||||
@ -116,8 +116,85 @@ const groupByAsTables = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const groupByExportError = () => {
|
||||
let table = {}
|
||||
try {
|
||||
table = new Table({
|
||||
id: 'XYZ',
|
||||
label: 'Test Table',
|
||||
rows: [
|
||||
{ id: 'abc', data: 'row', contractor: 'AshBritt' },
|
||||
{ id: 'qwe', data: 'lh', contractor: 'AshBritt' },
|
||||
]
|
||||
})
|
||||
} 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
|
||||
}
|
||||
|
||||
try {
|
||||
groupByNodule.export()
|
||||
return false
|
||||
} catch (err) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
const groupByAsTableError = () => {
|
||||
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
|
||||
}
|
||||
|
||||
try {
|
||||
groupByNodule.asTable()
|
||||
return false
|
||||
} catch (err) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default [
|
||||
{ name: 'Entity | GroupBy Value', test: groupByTest },
|
||||
{ name: 'Entity | GroupBy As Table', test: groupByAsTables },
|
||||
{ name: 'Entity | GroupBy export() should error out', test: groupByExportError },
|
||||
{ name: 'Entity | GroupBy asTable() should error out', test: groupByAsTableError },
|
||||
]
|
||||
@ -1,5 +1,5 @@
|
||||
import JoinNodule from '../../../src/entities/nodules/JoinNodule.js'
|
||||
import Table from '../../../src/entities/Table.js'
|
||||
import JoinNodule from '../../../src/entities/nodules/JoinNodule'
|
||||
import Table from '../../../src/entities/Table'
|
||||
|
||||
const joinTables = () => {
|
||||
const pickupTable = new Table({
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import Table from '../../../lib/entities/Table.js'
|
||||
import TransformNodule from '../../../lib/entities/nodules/TransformNodule.js'
|
||||
import Table from '../../../src/entities/Table'
|
||||
import TransformNodule from '../../../src/entities/nodules/TransformNodule'
|
||||
|
||||
const transformTable = () => {
|
||||
const expectedOutput = [
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import Table from '../../src/entities/Table.js'
|
||||
import Table from '../../src/entities/Table'
|
||||
|
||||
const input = {
|
||||
id: 'abc',
|
||||
|
||||
@ -1,15 +1,17 @@
|
||||
// import ProgressBar from 'progress'
|
||||
|
||||
import tableTests from '../tests/core/tableTests.js'
|
||||
import noduleTests from '../tests/core/NoduleTests.js'
|
||||
import filterNoduleTests from '../tests/core/nodules/filterNoduleTests.js'
|
||||
import joinNoduleTests from '../tests/core/nodules/joinNoduleTests.js'
|
||||
import transformNoduleTests from '../tests/core/nodules/transformNoduleTests.js'
|
||||
import groupByNoduleTests from '../tests/core/nodules/groupByNoduleTests.js'
|
||||
import tableTests from './core/tableTests.js'
|
||||
import noduleTests from './core/NoduleTests.js'
|
||||
import filterNoduleTests from './core/nodules/filterNoduleTests.js'
|
||||
import joinNoduleTests from './core/nodules/joinNoduleTests.js'
|
||||
import transformNoduleTests from './core/nodules/transformNoduleTests.js'
|
||||
import groupByNoduleTests from './core/nodules/groupByNoduleTests.js'
|
||||
|
||||
function runTestsAndReturnFailures (tests) {
|
||||
type unitTest = { name: string, test: Function }
|
||||
|
||||
function runTestsAndReturnFailures (tests: unitTest[]): string[] {
|
||||
const testTotalCount = tests.length
|
||||
const testsFailed = []
|
||||
const testsFailed: string[] = []
|
||||
|
||||
for (let i = 0; i < testTotalCount; i++) {
|
||||
const passedTest = tests[i].test()
|
||||
@ -18,7 +20,7 @@ function runTestsAndReturnFailures (tests) {
|
||||
return testsFailed
|
||||
}
|
||||
|
||||
function init (tests) {
|
||||
function init (tests: unitTest[]) {
|
||||
const failedTestsResults = runTestsAndReturnFailures(tests)
|
||||
if (failedTestsResults.length === 0) {
|
||||
console.log('\x1b[32m%s\x1b[0m', 'All Tests Passed!!')
|
||||
12
tsconfig.json
Normal file
12
tsconfig.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "commonjs",
|
||||
"declaration": true,
|
||||
"outDir": "./lib",
|
||||
"strict": true,
|
||||
"allowJs": true
|
||||
},
|
||||
"include": ["src", "tests"],
|
||||
"exclude": ["node_modules", "tests"]
|
||||
}
|
||||
@ -5,7 +5,7 @@ module.exports = {
|
||||
output: {
|
||||
path: path.resolve(__dirname),
|
||||
filename: 'index.js',
|
||||
library: 'dmein',
|
||||
library: 'lovelace',
|
||||
libraryTarget: 'umd',
|
||||
globalObject: 'this',
|
||||
umdNamedDefine: true
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user