Is there a way to do this inside Memgraph with triggers? - triggers

When calling a query module from a trigger statement, what I expected to get within a function was a state of the graph before the query changes occurred. However, this is not the case, and made changes are already visible in the graph state. I’ll write a dummy example of such behavior:
CREATE TRIGGER my_trigger ON CREATE
BEFORE COMMIT EXECUTE
CALL my_module.function(createdVertices, createdEdges) YIELD node, property
SET node.property = property;
Function my_module.function should execute after following statement:
MATCH (n {id: 19}), (m {id: 10}), (u {id: 14})
CREATE (n)-[new_edge_1:RELATION]->(m), (n)-[new_edge_2:RELATION]->(u)
In my_module.function, we’ll see a graph state with just created new_edge_1 and new_edge_2. If our calculation depends on having incremental changes, where we need the state of graph before any changes occur, is there a way to do it inside Memgraph with triggers?

Unfortunately, there is no way to do that with the triggers. During a single transaction, the changes of each query are visible in the next query. Triggers basically execute their statements as a query that is part of that transaction (if the BEFORE COMMIT is used).
You could probably use the changed values and ignore edges that are created in that transaction.

Related

Postgresql trigger function that queries data from a second table with possible race condition

I need to produce a trigger function that will fire, probably after update on one table that uses the data returned by that row insert to query data from a second table and return that data to the user.
Putting the function together should be OK I think, but, there is the possibility that the second table may not have the required data yet (I can't be sure the second table will be updated before this trigger fires).
Is there a way I can capture the fact that the return is null and put in a wait to try again a short time later?
Not getting any sense as to how I can do this from my searching.
OK, more contexts as requested. The tables are being loaded by an external process which reads csv files and imports the data into the database. The order of loading is not consistent so I can't (I don't think) rely on the second table being loaded when the trigger on the target tables fires.

Flutter floor database: The select * query that returns a stream is not updated upon deleting a record

Using the floor package for flutter:
https://pub.dev/packages/floor
When trying to delete a record from a table ex."Car" using the below SQL statement, the record is deleted but the reactive stream that monitors changes in the table doesn't get updated.
#Query('DELETE FROM Car WHERE Id=:Id')
Future<void> deleteById(int id);
#Query('SELECT * FROM Car')
Stream<List<Car>?> getAllCars();
For some reason, the generated code in the DB.g.dart file does not notify the changeListener if you attempt to insert, modify or delete a record using SQL query statements.
Thus, you should only use the #insert/update/delete methods for now, at least for version floor: ^1.2.0
Or, you can edit the DB.g.dart by adding changeListener.add('entity_name'); in every generated method that does changes in order to receive updates on your Stream. However, upon every regeneration of the DB.g.dart, you must remember to rewrite those edits again.

automatically change column values to lower case while inserting

I have a table in db2 which is having a varchar column. I want to insert only lower case string in the column.
Is it possible to change the case to lower whenever an insertion happens in that column. What will be the alter
Query for that if possible ?
I can not make another column which can take reference of my current column and be referenced like ucase(Current_column)
The means to ensure the effect of lower-casing the data that is inserted into a column, i.e. "to change the case to lower whenever an insertion happens in that column", is a TRIGGER.
Presumably much like Why is my “before update” trigger changing unexpected columns?, per having noted in a followup comment to the OP that "I tried making a BEFORE INSERT", a TRIGGER similar to the following apparently was implemented in that attempt?:
CREATE TRIGGER TOLOWER_BI BEFORE INSERT ON USERS
REFERENCING NEW AS N OLD AS O FOR EACH ROW MODE DB2ROW
set N.LoginId= lcase(N.LoginId)
If so, then "the application is not picking the trigger" [also from a followup comment to the OP] must be explained, because a TRIGGER is in effect at the database layer, such that an application has no choice [no picking] with regard to the effects of the trigger being enforced.

How to check if database row value has changed before doing a fill on a dataset

When I try to update a database with some modified values in a dataset, a concurrence exception doesn't raise if i change manually some values in the database after the fill method on the dataset is performed. (I only get the exception if I delete a row manually and then I try call the method update of data adapter).
How should I check if I have a "dirty read" on my dataset?.
You have several options.
Keeping a copy of the original entity set to compare against and make
the is dirty determination at the point you need to know whether it's
dirty.
Checking the datarow's rowstate property and if Modified compare
the values in the Current and Original DataRowVersions. If the second
change makes the value the same as the original then you could call
RejectChanges, however that would reject all changes on the row. You
will have to manually track each field since the dataset only keeps
per-row or per-table changes.

atk4.2 form submit-how to get new record id before insert to pass in arguments

I am referencing the 2 step newsletter example at http://agiletoolkit.org/codepad/newsletter. I modified the example into a 4 step process. The following page class is step 1, and it works to insert a new record and get the new record id. The problem is I don't want to insert this record into the database until the final step. I am not sure how to retrieve this id without using the save() function. Any ideas would be helpful.
class page_Ssp_Step1 extends Page {
function init(){
parent::init();
$p=$this;
$m=$p->add(Model_Publishers);
$form=$p->add('Form');
$form->setModel($m);
$form->addSubmit();
if($form->isSubmitted()){
$m->save();//inserts new record into db.
$new_id=$m->get('id');//gets id of new record
$this->api->memorize('new_id',$new_id);//carries id across pages
$this->js()->atk4_load($this->api->url('./Step2'))->execute();
}
}
}
There are several ways you could do this, either using atk4 functionality, mysql transactions or as a part of the design of your application.
1) Manage the id column yourself
I assume you are using an auto increment column in MySQL so one option would be to not make this auto increment but use a sequence and select the next value and save this in your memorize statement and add it in the model as a defaultValue using ->defaultValue($this->api->recall('new_id')
2) Turn off autocommit and create a transaction around the inserts
I'm from an oracle background rather than MySQL but MySQL also allows you to wrap several statements in a transaction which either saves everything or rollsback so this would also be an option if you can create a transaction, then you might still be able to save but only a complete transaction populating several tables would be committed if all steps complete.
In atk 4.1, the DBlite/mysql.php class contains some functions for transaction support but the documentation on agiletoolkit.org is incomplete and it's unclear how you change the dbConnect being used as currently you connect to a database in lib/Frontend.php using $this->dbConnect() but there is no option to pass a parameter.
It looks like you may be able to do the needed transaction commands using this at the start of the first page
$this->api->db->query('SET AUTOCOMMIT=0');
$this->api->db->query('START TRANSACTION');
then do inserts in various pages as needed. Note that everything done will be contained in a transaccion so if the user doesnt complete the process, nothing will be saved.
On the last insert,
$this->api->db->query('COMMIT');
Then if you want to, turn back on autocommit so each SQL statement is committed
$this->api->db->query('SET AUTOCOMMIT=1');
I havent tried this but hopefully that helps.
3) use beforeInsert or afterInsert
You can also look at overriding the beforeInsert function on your model which has an array of the data but I think if your id is an auto increment column, it won't have a value until the afterInsert function which has a parameter of the Id inserted.
4) use a status to indicate complete record
Finally you could use a status column on your record to indicate it is only at the first stage and this only gets updated to a complete status when the final stage is completed. Then you can have a housekeeping job that runs at intervals to remove records that didn't complete all stages. Any grid or crud where you display these records would be limited with AddCondition('status','C') in the model or added in the page so that incomplete ones never get shown.
5) Manage the transaction as non sql
As suggested by Romans, you could store the result of the form processing in session variables instead of directly into the database and then use a SQL to insert it once the last step is completed.