mirror of https://github.com/joomla/joomla-cms.git
148 lines
4.6 KiB
JavaScript
148 lines
4.6 KiB
JavaScript
const mysql = require('mysql');
|
|
const postgres = require('postgres');
|
|
|
|
// Items cache which are added by an insert statement
|
|
let insertedItems = [];
|
|
|
|
/**
|
|
* Does run the given query against the database from the configuration. It caches all inserted items.
|
|
*
|
|
* @param {string} query
|
|
* @param {object} config The config
|
|
* @returns Promise
|
|
*/
|
|
function queryTestDB(joomlaQuery, config) {
|
|
// Substitute the joomla table prefix
|
|
let query = joomlaQuery.replaceAll('#__', config.env.db_prefix);
|
|
|
|
// Parse the table name
|
|
const tableNameOfInsert = query.match(/insert\s+into\s+(.*?)\s/i);
|
|
|
|
// Find an inserted item
|
|
let insertItem = tableNameOfInsert && tableNameOfInsert.length > 1 && insertedItems.find((item) => item.table === tableNameOfInsert[1]);
|
|
|
|
// If it is an insert query, but there is no cache object, create one
|
|
if (tableNameOfInsert && tableNameOfInsert.length > 1 && !insertItem) {
|
|
insertItem = { table: tableNameOfInsert[1], rows: [] };
|
|
|
|
// Push it to the cache
|
|
insertedItems.push(insertItem);
|
|
}
|
|
|
|
// Check if the DB is from postgres
|
|
if (config.env.db_type === 'pgsql' || config.env.db_type === 'PostgreSQL (PDO)') {
|
|
const connection = postgres({
|
|
host: config.env.db_host,
|
|
port: config.env.db_port,
|
|
database: config.env.db_name,
|
|
username: config.env.db_user,
|
|
password: config.env.db_password,
|
|
idle_timeout: 1,
|
|
max_lifetime: 1,
|
|
});
|
|
|
|
// Postgres delivers the data direct as result of the insert query
|
|
if (insertItem) {
|
|
query += ' returning *';
|
|
}
|
|
|
|
// Postgres needs double quotes
|
|
query = query.replaceAll('`', '"');
|
|
|
|
return connection.unsafe(query).then((result) => {
|
|
// Select query should always return an array
|
|
if (query.indexOf('SELECT') === 0 && !Array.isArray(result)) {
|
|
return [result];
|
|
}
|
|
|
|
if (!insertItem || result.length === 0) {
|
|
return result;
|
|
}
|
|
|
|
// Push the id to the cache when it is an insert operation
|
|
if (insertItem && result.length && result[0].id) {
|
|
insertItem.rows.push(result[0].id);
|
|
}
|
|
|
|
// Normalize the object
|
|
return { insertId: result[0].id };
|
|
});
|
|
}
|
|
|
|
// Return a promise which runs the query
|
|
return new Promise((resolve, reject) => {
|
|
// Create the connection and connect
|
|
const connection = mysql.createConnection({
|
|
host: config.env.db_host,
|
|
port: config.env.db_port,
|
|
user: config.env.db_user,
|
|
password: config.env.db_password,
|
|
database: config.env.db_name,
|
|
});
|
|
|
|
// Perform the query
|
|
connection.query(query, (error, results) => {
|
|
connection.end();
|
|
|
|
// Reject when an error
|
|
if (error && error.errno) {
|
|
return reject(error);
|
|
}
|
|
|
|
// Push the id to the cache when it is an insert operation
|
|
if (insertItem && results && results.insertId) {
|
|
insertItem.rows.push(results.insertId);
|
|
}
|
|
|
|
// Resolve the result
|
|
return resolve(results);
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Deletes the inserted items from the database.
|
|
*
|
|
* @param {object} config The configuration
|
|
*
|
|
* @returns null
|
|
*/
|
|
function deleteInsertedItems(config) {
|
|
// Holds the promises for the deleted items
|
|
const promises = [];
|
|
|
|
// Loop over the cached items
|
|
insertedItems.forEach((item) => {
|
|
// When there is nothing to delete, ignore it
|
|
if (item.rows.length < 1) {
|
|
return;
|
|
}
|
|
|
|
// Delete the items from the database
|
|
promises.push(queryTestDB(`DELETE FROM ${item.table} WHERE id IN (${item.rows.join(',')})`, config).then(() => {
|
|
// Cleanup some tables we do not have control over from inserted items
|
|
if (item.table === `${config.env.db_prefix}users`) {
|
|
promises.push(queryTestDB(`DELETE FROM #__user_usergroup_map WHERE user_id IN (${item.rows.join(',')})`, config));
|
|
promises.push(queryTestDB(`DELETE FROM #__user_profiles WHERE user_id IN (${item.rows.join(',')})`, config));
|
|
}
|
|
|
|
if (item.table === `${config.env.db_prefix}content`) {
|
|
promises.push(queryTestDB(`DELETE FROM #__content_frontpage WHERE content_id IN (${item.rows.join(',')})`, config));
|
|
promises.push(queryTestDB(`DELETE FROM #__workflow_associations WHERE item_id IN (${item.rows.join(',')}) AND extension = 'com_content.article'`, config));
|
|
}
|
|
|
|
if (item.table === `${config.env.db_prefix}modules`) {
|
|
promises.push(queryTestDB(`DELETE FROM #__modules_menu WHERE moduleid IN (${item.rows.join(',')})`, config));
|
|
}
|
|
}));
|
|
});
|
|
|
|
// Clear the cache
|
|
insertedItems = [];
|
|
|
|
// Return the promise which waits for all delete queries
|
|
return Promise.all(promises);
|
|
}
|
|
|
|
module.exports = { queryTestDB, deleteInsertedItems };
|