I'm discovering Express by creating a simple CRUD without ORM.
Issue is, I'm not able to find any record through the Model.findBy() function
model User {
static async findBy(payload) {
try {
let attr = Object.keys(payload)[0]
let value = Object.values(payload)[0]
let user = await pool.query(
`SELECT * from users WHERE $1::text = $2::text LIMIT 1;`,
[attr, value]
);
return user.rows; // empty :-(
} catch (err) {
throw err
}
}
}
User.findBy({ email: 'foo#bar.baz' }).then(console.log);
User.findBy({ name: 'Foo' }).then(console.log);
I've no issue using psql if I surround $2::text by single quote ' like:
SELECT * FROM users WHERE email = 'foo#bar.baz' LIMIT 1;
Though that's not possible inside parametrized queries. I've tried stuff like '($2::text)' (and escaped variations), but that looks far from what the documentation recommends.
I must be missing something. Is the emptiness of user.rows related to the way I fetch attr & value ? Or maybe, is some kind of escape required when passing string parameters ?
"Answer":
As stated in the comment section, issue isn't related to string escape, but to dynamic column names.
Column names are not identifiers, and therefore cannot be dynamically set using a query parameter.
See: https://stackoverflow.com/a/50813577/11509906
Delete multiple entries from DB using Groovy in SoapUI
I am able to execute one SQL statement, but when I do a few it just hangs.
How can I delete multiple rows?
def sql = Sql.newInstance('jdbc:oracle:thin:#jack:1521:test1', 'test', 'test', 'oracle.jdbc.driver.OracleDriver')
log.info("SQL connetced")
sql.connection.autoCommit = false
try {
log.info("inside try")
log.info("before")
String Que =
"""delete from table name where user in (select user from user where ID= '123' and type= 262);
delete from table name where user in (select user from user where ID= '1012' and type= 28)
delete from table name where user in (select user from user where ID= '423' and type= 27)
"""
log.info (Que)
def output = sql.execute(Que);
log.info(sql)
log.info(output)
log.info("after")
sql.commit()
println("Successfully committed")
}catch(Exception ex) {
sql.rollback()
log.info("Transaction rollback"+ex)
}
sql.close()
Here is what you are looking for.
I feel it is more effective way if you want bulk number of records using the following way.
Create a map for the data i.e., id, type as key value pair that needs to be removed in your case.
Used closure to execute the query by iterating thru it.
Added comments appropriately.
//Closure to execute the query with parameters
def runQuery = { entry ->
def output = sql.execute("delete from table name where user in (select user from user where ID=:id and type=:type)", [id:entry.key, type:entry.value] )
log.info(output)
}
//Added below two statements
//Create the data that you want to remove in the form of map id, and type
def deleteData = ['123':26, '1012':28, '423':27]
def sql = Sql.newInstance('jdbc:oracle:thin:#jack:1521:test1', 'test', 'test', 'oracle.jdbc.driver.OracleDriver')
log.info("SQL connetced")
sql.connection.autoCommit = false
try {
log.info(sql)
log.info("inside try")
log.info("before")
//Added below two statements
//Call the above closure and pass key value pair in each iteration
deleteData.each { runQuery(it) }
log.info("after")
sql.commit()
println("Successfully committed")
}catch(Exception ex) {
sql.rollback()
log.info("Transaction rollback"+ex)
}
sql.close()
If you are just looking after execution of multiple queries only approach, then you may look at here and not sure if your database supports the same.
I want to delete one row from one of my tables, based on a form -> "username".Let's assume, i have a log in page, where i write into the fields the apropriate username, and password based on a database which contains these values. After log in, i want to log out. And then I want to delete from the table the username and passwrod i used to sign in. How can i do it? Here's my code, it's unfortunately delete all the rows from the table. I have tried many ways... please help.
$sql="DELETE FROM login WHERE username='username'" ;
$result = mysqli_query($sqlconnection,$sql) or die...
assume that you receive the username value by a form by post and assign the value to a vars
$username = $_SESSION['login_user'];
then you can pass the value to you query this way
$sql="DELETE FROM login WHERE username='$username';" ;
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// sql to delete a record
$sql="DELETE FROM login WHERE username='$username';" ;
if ($conn->query($sql) === TRUE) {
echo "Record deleted successfully";
} else {
echo "Error deleting record: " . $conn->error;
}
Ok so basically I need to convert this regular sql statement to the syntax joomla uses via
https://api.joomla.org/11.4/Joomla-Platform/Database/JDatabaseQuery.html
here is my statement
SET #myunsubid = (
SELECT subid
FROM aqbi8_acymailing_subscriber s
WHERE s.email = 'email#email.co.nz'
);
SELECT #myunsubid;
UPDATE aqbi8_acymailing_listsub a
SET a.`status` = 1
WHERE a.subid = #myunsubid AND a.listid = 232
So id like it to be like
$db->set(#myunsubid = ( $db->select($db->quoteName('subid') )
$db->from($db->quoteName('aqbi8_acymailing_subscriber s') )
$db->where($db->quoteName('s.email') = 'email#email.co.nz')
)
$db->update($db->quoteName('aqbi8_acymailing_listsub a'))
$db->set($db->quoteName('a.status') = 1)
$db->where ($db->quoteName('a.subid') = #myunsubid AND $db->quoteName('a.listid') = 232 )
But this isnt quite right. please help!
I actually figured it out got it to work like this.
$db = &JDatabase::getInstance($option);
$query = $db->getQuery(true);
// make a variable for subID
$query->select($db->quoteName(array('subid')));
$query->from($db->quoteName('aqbi8_acymailing_subscriber'));
$query->where($db->quoteName('email') . " = '" . $email ."'");
$db->setQuery($query);
$db->execute();
$test = $db->loadObjectList();
print_r( $test );
$myid = $test[0]->subid;
$query->clear();
// // Create Database query
$fields = $db->quoteName('status') . ' = 1';
$conditions = array(
$db->quoteName('subid') . ' = ' . $myid,
$db->quoteName('listid') . ' = ' . $listid
);
// // update query
$query->update($db->quoteName('aqbi8_acymailing_listsub'))->set($fields)->where($conditions);
$db->setQuery($query);
$db->execute();
You don't need to make two trips to the database, you can write a subquery into your UPDATE's WHERE condition (no mysql variables or table aliases are necessary).
Raw Query:
UPDATE aqbi8_acymailing_listsub
SET status = 1
WHERE listid = 232
AND subid = (
SELECT subid
FROM aqbi8_acymailing_subscriber
WHERE `email` = 'email#email.co.nz'
)
Tested Code:
$db = JFactory::getDBO();
try {
$subquery = $db->getQuery(true)
->select('subid')
->from('#__acymailing_subscriber')
->where("email = 'email#email.co.nz'");
$query = $db->getQuery(true)
->update("#__acymailing_listsub")
->set("status = 1")
->where(["listid = 232", "personid = ($subquery)"]); // or make 2 where() calls
echo $query->dump(); // if you want to see; *during development ONLY
$db->setQuery($query);
$db->execute();
if ($affrows = $db->getAffectedRows()) {
JFactory::getApplication()->enqueueMessage("Updated. Rows affected: $affrows", 'success');
} else {
JFactory::getApplication()->enqueueMessage("Logic Error", 'error');
}
} catch (Exception $e) {
JFactory::getApplication()->enqueueMessage("Query Syntax Error: " . $e->getMessage(), 'error'); // never show getMessage() to public
}
It is not clear if any of your values are coming from users/untrusted sources, so be sure to follow good practices when writing variables into your queries -- like casting integers with (int) and calling $db->quote() on string values.
If you want to see a complex/convoluted UPDATE query with several other tables and techniques blended in, here is a comprehensive post: https://joomla.stackexchange.com/a/22916/12352
Please DON'T USE JDatabase Object to update Joomla tables, when there's an API available for the extension.
Whilst I appreciate the OP's question is pertaining to how to update the joomla database using the joomla database object (JDatabase), I propose a safer and more robust method, the "ACYMailing API".
"BUT WHY?", I hear you ask...
Good question!!!
There are 2 pitfalls in updating the joomla database directly - be it on the command-line, in a GUI such as MySQL Workbench or PHPMyAdmin, or even with the Joomla Database Object. Simply put, they both concern compatibility - 1. regarding third party integrations, and 2. concerning the future compatibility of your code. In a nutshell, whenever there's a an API for interacting with a component, I'd use it, over JDatabase every time to future proof your code, and ensure that all pre and post save, update, delete... ...move, and publish plugin events take care of your integrations, just as if you'd performed the action authentically.
To elaborate on these points a bit...
Most Joomla extensions (core and 3rd-party) make use of Joomla's powerful plugin architecture. By doing so, extensions can perform actions at key points in the application's life cycle. For example, after deleting a record from a table belonging to component1, delete related records from a table relating to compnent2. Therefore, one run's the risk of breaking the behaviour/functionality of the component in question - i.e. ACY Mailing, as in your case. Potentially, other core/3rd-party extensions that rely on ACY's data, that would otherwise, get updated through onAfterSave() or onAfterDelete() plugin events, as they will not get called.
There's a big risk that your code to break with future Joomla/ACY Mailing updates, if/when the table structure changes.
OK, so how do we use the API?
The following example code displays everything that you should need to update a subscription record. Each step explains the code, which for reference, is summarised in doc and inline comments in the code itself. To begin, navigate to the file where you are entering your code, then...
STEP BY STEP
STEP 1: Check the existence of ACY Mailing by attempting to include it's helper class, as follows. N.B. If the include_once() fails, you should see the echo statement, indicating that ACY Mailing IS NOT installed.
// load the ACY Mailing helper - bail out if not
if(!include_once(rtrim(JPATH_ADMINISTRATOR, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'components' . DIRECTORY_SEPARATOR . 'com_acymailing' . DIRECTORY_SEPARATOR . 'helpers' . DIRECTORY_SEPARATOR . 'helper.php')){
echo 'This code can not work without the AcyMailing Component';
return false;
}
STEP 2: Set-up your parameters by inputting values into the following 3 variables. See examples in code comments.
// array $lists An array of integer IDs (primary keys) of the lists you want the user to be subscribed to (can be empty).
// e.g. array(2,4,6)
$lists = array();
// array $unsubs An array of integer IDs (primary keys) of the lists you want the user to be un-subscribed from (can be empty).
// e.g. array(2,4,6)
$unsubs = array();
// string $userID Numeric Joomla User or user e-mail. For example: '42' or 'name#domain.com'
$userID = '';
STEP 3: Add the following code to find the ACY Mailing user, from the Joomla User ID/Email address passed in to the ->subid() method, and bail out if not found.
// instantiate the ACY Mailing Subscriber (user) Class
$user = acymailing_get('class.subscriber');
// find the ACY Mailing user id (subid) from the joomla ID or email address set in $userID
$subID = $user->subid($userID);
// No ACY Mailing user/subscriber?
if(empty($subID))
return; // bail out
STEP 4: Add the following code to check, and setup the data for any of the subscriptions/unsubscriptions you've configured to update ($lists and $unsubs arrays). If any found, they will be updated. If not found, return.
// create an array to store data in
$data = array();
// Set up new newsletter subscriptions from the $lists array()
if(!empty($lists)) foreach($lists as $listId)
$data[$listId] = array("status" => 1);
// Set up un-subscriptions from the $unsubs array()
if(!empty($unsubs)) foreach($unsubs as $listId)
$data[$listId] = array('status' => 0);
// no data, bail out...
if(empty($data))
return; //there is nothing to do...
// update the user's subscription records, creating/removing subscriptions/unsubsriptions accordingly
$user->saveSubscription($subID, $data);
I changed this login script to PDO. Now it passes the username but get's stuck fetchAll line. I need help please. thanks
<?php
session_start();
include_once"includes/config.php";
if (isset($_POST['admin_login'])) {
$admin_user = trim($_POST['admin_user']);
$admin_pw = trim($_POST['admin_pw']);
if ($admin_user == NULL OR $admin_pw == NULL) {
$final_report.="Please complete all the fields below..";
} else {
$check_user_data = $db->prepare("SELECT * FROM `admin`
WHERE `admin_user`='$admin_user'");
$check_user_data->execute();
if ($check_user_data->fetchColumn() == 0) {
$final_report.="This admin username does not exist..";
} else {
$get_user_data = $check_user_data->fetchAll($check_user_data);
if ($get_user_data['admin_pw'] == $admin_pw) {
$start_idsess = $_SESSION['admin_user'] = "".$get_user_data['admin_user']."";
$start_passsess = $_SESSION['admin_pw'] = "".$get_user_data['admin_pw']."";
$final_report.="You are about to be logged in, please wait a few moments...";
header('Location: admin.php');
}
}
}
}
?>
Not checking return value prepare() or execute() for false. You need to check for SQL errors and handle them, stopping the code instead of continuing on blithely.
Not using query parameters in the prepared statement, still interpolating $_POST content into the query unsafely. You're missing the benefit of switching to PDO, and leaving yourself vulnerable to SQL injection attack.
You're storing passwords in plaintext, which is unsafe. See You're Probably Storing Passwords Incorrectly.
Do you really need to SELECT * if you only use the admin_pw column? Hint: no.
PDOStatement::fetchAll() returns an array of arrays, not just one array for a row. Read the examples in the documentation for fetchAll().