lamed_table
Version:
Light table implementation
373 lines (342 loc) • 11.9 kB
JavaScript
// Comment out in test functions
console.log(`Starting ${__filename}...`) // comment line to remove simple logging
/* ------------------------------------------------------
* tableFunctions.js
* Purpose: The purpose of this module is to implement functions for the table object
* Date Created: 2019/12/12
* Created by : Perez Lamed van Niekerk
--------------------------------------------------------- */
/* jshint esversion: 6 */
const _test = require('lamed_test')
const { Ok, notOk, notOk_Then, Equal, notEqual, con, testAND, unZip } = _test // eslint-disable-line
// con.setupChalk(require('chalk'))
// con.traceSet(0)
const _name = require('lamed_name')
const _cols = require('./tableCols')
const _format = require('io_format')
// const _lio = require('lamed_io')
/**
* Create an empty table object
* @param {string} tableName - the table name
*/
function createEmpty (tableName = 'tableName') {
const table = { name: tableName, cols: [], rows: [] }
return table
}
/**
* Create a table object with the specified columns
* @param {array} columns - string array of the columns to add
* @param {string} tableName - table name.
*/
function create (columns, tableName = 'tableName') {
if (Array.isArray(columns) === false) columns = [columns]
// if (columns.length === 0) throw new Error('Cannot create table with no columns!\n')
const table = createEmpty(tableName)
_cols.colsCreate(table, columns)
checkTableData(table)
return table
}
/**
* Show the data within a table
* @param {table} table - The table object
* @param {bool} show - If true, show the output
* @param {int} rowCount - The max rows to show. Default = -1 (all rows)
* @param {int} colCount - The max cols to show. Default = -1 (all cols)
* @param {int} maxColLength - The maximum length of a col. Default = -1 (not trimming)
* @returns {void} - Nothing but output table to the console
*/
function showTable (table, show = true, rowCount = -1, colCount = -1, maxColLength = -1) {
if (show === false) return
const name = table.name
// Get cols & rows
let cols = table.cols
let rows = table.rows
if (rowCount !== -1 || colCount !== -1 || maxColLength !== -1) {
if (rowCount === -1) rows = table.rows.slice(0)
else rows = table.rows.slice(0, rowCount)
}
if (rowCount === -1) rowCount = rows.length
// colCount
if (colCount === -1) colCount = cols.length
else {
for (let ii = 0; ii < rows.length; ii++) {
rows[ii] = rows[ii].slice(0, colCount)
}
if (colCount < cols.length) {
cols = cols.slice(0, colCount)
cols[colCount - 1] = cols[colCount - 1] + '...'
}
}
// maxColLength
if (maxColLength !== -1) {
// con.log({maxColLength})
for (let ii = 0; ii < rows.length; ii++) {
let row = rows[ii]
row = row.map(x => _format.formatLine(x, maxColLength)) // Trim cell values
rows[ii] = row
// con.log({row})
}
}
con.log('')
con.logHeading(`Table: ${name}`)
if (Ok(table.count)) {
const count = table.count
if (Ok(table.totalCol)) {
const totalCol = table.totalCol
const min = table.min
const max = table.max
const sum = table.sum
const avg = table.avg
con.log({ name, cols, totalCol, count, min, max, sum, avg })
} else con.log({ name, cols, count })
} else {
// Show cols
// cols.map((x, ii) => con.logGreen(`${ii} ${x}`))
let heading = ''
cols.map((x, ii) => heading += `${ii}.'${x}', `) // eslint-disable-line
con.logHeading(heading, true)
// con.logHeading(cols.join(', '), true)
}
con.logTable(rows)
if (colCount < table.cols.length) con.log(` (displaying ${colCount} / ${table.cols.length} columns)`)
if (rowCount < table.rows.length) con.log(` (displaying ${rowCount} / ${table.rows.length} rows)`)
con.logLine()
}
/**
* Show tracing information about the table object
* @param {object} table - table object
* @param {boolean} showTrace - If true, show trace information
* @param {boolean} showError - If true throw error when table is not a table
*/
function TableCheck (table, showTrace = false, showError = true) {
return checkTableData(table.DATA, showTrace, showError)
}
/**
* Show tracing information about the table object
* @param {object} tableData - table object
* @param {boolean} showTrace - If true, show trace information
* @param {boolean} showError - If true throw error when table is not a table
*/
function checkTableData (tableData, showTrace = false, showError = true) {
const name = tableData.name
const cols = tableData.cols
const rows = tableData.rows
const isTable = (Ok(name) && cols !== undefined && rows !== undefined)
if (isTable === false && showError) showTrace = true
showTable(tableData, showTrace)
if (isTable === false && showError) throw new Error('in checkTableData(). input parameter is not a table\n')
return isTable
}
// /**
// * Sort table ascending on the specified columns
// * @param {object} table - The Table object
// * @param {string / number} colNamesOrNumbers - The columns names or the numbers to sort on
// */
// function sortFields (table, colNamesOrNumbers, acending = true) {
// if (Array.isArray(colNamesOrNumbers) === false) throw new Error('colNamesOrNumbers must be an array')
// let colNames = colNamesOrNumbers.reverse()
// for (let ii = 0; ii < colNames.length; ii++) {
// let colName = colNames[ii]
// sort(table, colName, acending)
// }
// }
/**
* Sort table ascending on the specified column
* @param {object} table - The Table object
* @param {string / number} colNameOrNumber - The column number or the the name
*/
function sort (table, colNameOrNumber, acending = true) {
checkTableData(table, false, true)
const colNo = _cols.colsNumber(table.cols, colNameOrNumber)
if (acending) table.rows.sort((a, b) => sortAsc1(a, b, colNo))
else table.rows.sort((a, b) => sortDec1(a, b, colNo))
}
function sortAsc1 (a, b, col = 0) {
if (a[col] === b[col]) return 0
else return (a[col] < b[col]) ? -1 : 1
}
function sortDec1 (a, b, col = 0) {
if (a[col] === b[col]) return 0
else return (a[col] > b[col]) ? -1 : 1
}
/**
* Convert a array table to markdown table
* @param {object} table - The table object
* @param {string / number} boldCol - The col name or number to bold
* @param {string} heading - The heading to use for the markdown table. Default = table name
*/
function table2MD (table, boldColumn = -1, heading = '') {
const boldCol = _cols.colsNumber(table.cols, boldColumn)
if (notOk(heading)) {
// Lets build heading from the table name
heading = table.name
heading = _name.name2Heading(heading)
heading = `## ${heading}`
}
let result = `${heading}\n\n| `
let header = '| '
for (let ii = 0; ii < table.cols.length; ii++) {
let item = table.cols[ii]
item = _name.name2Heading(item)
result += item + ' |'
header += ' ---- |'
}
result += '\n' + header + '\n'
for (let ii = 0; ii < table.rows.length; ii++) {
const row = table.rows[ii]
for (let jj = 0; jj < row.length; jj++) {
let item = row[jj]
// con.log({item})
if (typeof item === 'string') {
item = item.trim()
item = item.replaceAll('\n', '<br>') // '\n' is not supported in markdown tables
}
if (jj === boldCol) item = `**${item}**`
result += item + ' |'
}
result += '\n'
}
// con.trace({result})
return result
}
// Convert table to CSV
/**
* Convert a table to CSV format
* @param {table} table - The table to convert
* @param {bool} addHeadings - If true, add the headings
*/
function Table2CSV (table, addHeadings = true) {
const result = []
if (addHeadings) result.push(table.cols.join(', '))
for (let ii = 0; ii < table.rows.length; ii++) {
const row = table.rows[ii]
result.push(row.join(', '))
}
return result.join('\r\n')
}
/**
* Return header information for the table
*/
function table2HTML_Header () { // eslint-disable-line
const result =
// ' <link rel="stylesheet" type="text/css" href="./DataTables/jquery-ui.css"/>\n'+
// ' <link rel="stylesheet" type="text/css" href="./DataTables/dataTables.jqueryui.min.css"/>\n'+
' <link rel="stylesheet" type="text/css" href="./cdn/jquery.dataTables.min.css"/>\n' +
' <script type="text/javascript" src="./cdn/jquery-3.3.1.js"></script>\n' +
' <script type="text/javascript" src="./cdn/jquery.dataTables.min.js"></script>\n'
return result
}
/**
* Return script for the table
*/
function table2HTML_Script (idName = 'dataTable') { // eslint-disable-line
const result =
'<script>\n' +
' $(document).ready(function() {\n' +
` $('#${idName}').DataTable({ autoFill: true, keys : true } );\n` +
' } );\n' +
'</script>\n'
return result
}
/**
* Convert a array table to HTML table
* @param {object} table - The table object
*/
function table2HTML (table, idName = 'dataTable', htmlClass = 'cell-border', addFooter = true, buildPage = true) {
htmlClass = 'display compact'
htmlClass = 'cell-border compact stripe hover'
let result = `<table id="${idName}" class="${htmlClass}" style="width:100%">\n`
let header = ' <tr> '
const header1 = '<th>'
const header2 = '</th> '
for (let ii = 0; ii < table.cols.length; ii++) {
let item = table.cols[ii]
item = _name.name2Heading(item)
header += header1 + item + header2
}
header += ' </tr>\n'
result += ' <thead>\n' + header + ' </thead>\n'
result += ' <tbody>\n'
let footer = ''
if (addFooter) footer = ' <tfoot>\n' + header + ' </tfoot>\n'
for (let ii = 0; ii < table.rows.length; ii++) {
let line = ' <tr> '
const row = table.rows[ii]
for (let jj = 0; jj < row.length; jj++) {
let item = row[jj]
// con.log({item})
if (typeof item === 'string') {
item = item.trim()
item = item.replaceAll('\n', '<br>') // '\n' is not supported in markdown tables
}
const value = '<td>' + item + '</td> '
// con.log({value})
line += value
}
line += ' </tr>\n'
// con.log({line})
result += line
}
result += ' </tbody>\n'
result += footer
result += '</table>\n\n'
// con.trace({result})
if (buildPage) {
result = '<html>\n<head>\n' + table2HTML_Header() + '</head>\n' +
'<body>\n' + result + table2HTML_Script() + '</body>\n</html>'
}
return result
}
/**
* Import items from a list into a table. This can be used to divide lists into columns
* @param {array} list - List of array
* @param {object} table - The table
*/
function TableArray2Columns (list, table) {
const total = table.totalCols()
// con.log({total})
let index = 0
let row = []
for (let ii = 0; ii < list.length; ii++) {
const item = list[ii]
table.Rows.Set(row, index, item)
index++
if (index === total) {
table.Rows.Add(row)
row = []
index = 0
}
}
}
/**
* Total columns in the table
* @param {object} table - The table object
* @returns {number} - the total columns in the table
*/
function totalCols (table) {
return table.cols.length
}
/**
* Total rows in the table
* @param {object} table - The table object
* @returns {number} - The total rows in the table
*/
function totalRows (table) {
return table.rows.length
}
// Exports --------------------------
module.exports = {
create,
showTable,
TableCheck,
checkTableData,
totalCols,
totalRows,
// Adding
TableArray2Columns,
// Format
sort,
table2MD,
Table2CSV,
table2HTML
}