sqlite-plugin-red
Version:
Adding a tab to show and edit the structure of a sqlite database. Needs node-red-node-sqlite.
185 lines (170 loc) • 5.2 kB
JavaScript
const { setError } = require('./error.js')
const getDefaultTable = () => {
return {
edit: false,
editTableName: false,
name: '',
oldName: '',
isNameUnique: true,
isNew: false,
header: [
{ name: 'id', edit: false },
{ name: 'Name', type: 'text' },
{
name: 'Type',
type: 'select',
options: [
{ value: 'TEXT', name: 'TEXT' },
{ value: 'INTEGER', name: 'INTEGER' },
{ value: 'BLOB', name: 'BLOB' },
{ value: 'REAL', name: 'REAL' },
{ value: 'NUMERIC', name: 'NUMERIC' },
],
},
{ name: 'Not null', type: 'checkbox'},
{ name: 'Primary key', type: 'checkbox'},
{ name: 'Autoincr.', type: 'checkbox'},
{ name: 'Unique', type: 'checkbox'}
],
rows: [],
disableCreation: true,
hasAutoincrement: false
}
}
const getIndexes = (header) => {
i = {
name: header.findIndex(h => h.name === 'Name'),
type: header.findIndex(h => h.name === 'Type' ),
notnull: header.findIndex(h => h.name === 'Not null' ),
pk: header.findIndex(h => h.name === 'Primary key' ),
ai: header.findIndex(h => h.name === 'Autoincr.' ),
unique: header.findIndex(h => h.name === 'Unique' )
}
return i
}
const createFieldSql = (row, indexes) => {
let fieldSql = ''
fieldSql += `"${row[indexes.name]}" ${row[indexes.type]}`
if (row[indexes.notnull]) fieldSql += ' NOT NULL'
if (row[indexes.unique]) fieldSql += ' UNIQUE'
return fieldSql
}
const createPrimaryFieldSql = (row, indexes, primaryKey='') => {
if (row[indexes.pk]) {
if (!primaryKey) {
primaryKey = ', PRIMARY KEY("' + row[indexes.name] + '"'
} else {
if (primaryKey.endsWith(')')) primaryKey = primaryKey.substring(0, primaryKey.length - 1)
primaryKey += ',' + row[indexes.name]
}
if (row[indexes.ai]) primaryKey += ' AUTOINCREMENT'
primaryKey += ')'
return primaryKey
}
return ''
}
const createFieldsSql = (table) => {
const header = table.header
const rows = table.rows
let fieldDef = ''
let primaryKey = ''
const indexes = getIndexes(header)
rows.forEach(row => {
if (fieldDef) fieldDef += ', '
fieldDef += createFieldSql(row, indexes)
primaryKey += createPrimaryFieldSql(row, indexes, primaryKey)
})
return '(' + fieldDef + ' ' + primaryKey + ')'
}
const createTableSql = (path, table, copyTableName) => {
const fieldSql = createFieldsSql(table)
if (!path) {
error = 'Database not found!'
setError(error)
throw new Error(error)
}
if (table.oldName) {
return `CREATE TABLE "__${table.name}_new" ${fieldSql};`
} else {
let name = table.name
if (copyTableName) name = copyTableName
return `CREATE TABLE "${name}" ${fieldSql};`
}
}
// const handleAutoincrement = (table, i) => {
// const rows = table.rows
// const index = getIndexes(table.header)
// // rows[i].ai = !rows[i].ai
// table.hasAutoincrement = rows[i].ai
// // like highlander... there can only be one (autoincr and then also only one pk)
// if (rows[i].ai) {
// rows.forEach((row, index) => {
// if (index === i) {
// row.type = 'INTEGER'
// row.pk = true
// } else {
// row.ai = false
// row.pk = false
// }
// })
// }
// return table
// }
const checkTableAndFieldName = (selected, table) => {
const index = getIndexes(table.header)
table.disableCreation = true
// check if name already in db
table.isNameUnique = true
selected.database.forEach(t => {
if (t.name.toLowerCase() === table.name.toLowerCase()) table.isNameUnique = false
})
const isFieldNameEmpty = !!(table?.rows.find(f => f[index.name].trim() === ''))
const fieldnames = table.rows.map(f => f[index.name])
const hasFieldNameDuplicates = fieldnames.some((val, i) => fieldnames.indexOf(val) !== i)
if (table.name && table.isNameUnique && !isFieldNameEmpty && !hasFieldNameDuplicates) {
table.disableCreation = false
}
return table
}
const prepareNewTable = (table, newTable) => {
table = getDefaultTable()
table.isNew = newTable
table.edit = newTable
table.name = ''
table.oldName = ''
return table
}
const prepareTable = (table, selected) => {
if (selected.table !== null) {
table = getDefaultTable()
table.name = selected.database[selected.table].name
const indexes = getIndexes(table.header)
selected.database[selected.table].columns.forEach((col, i) => {
const newRow = new Array(table.header.length).fill('')
newRow[0] = i
for (const [key, value] of Object.entries(col)) {
if (indexes[key]) newRow[indexes[key]] = value
}
table.rows.push(newRow)
})
}
return table
}
const prepareEditTableName = (table, selected) => {
table.editTableName = !table.editTableName
table.name = selected.database[selected.table].name
table.oldName = selected.database[selected.table].name
return table
}
module.exports = {
getDefaultTable,
getIndexes,
createFieldsSql,
createFieldSql,
createPrimaryFieldSql,
createTableSql,
checkTableAndFieldName,
prepareNewTable,
prepareTable,
prepareEditTableName
}