Is there a way to know if the Event Alerter is called locally or from other user, to avoid double refreshes? - firebird

I use Firebird 3 with IBDAC and try to use Alerter Event to refresh data from other user/users, is there a way to know if the Alerter is called locally or from other user, to avoid double refreshes?
It is a good feature to refresh data (mostly small lookup fields) when other user has changed over the network.
Code is like this:
procedure TdmTables.IBCAlerterEvent(Sender: TObject; EventName: string; EventCount: Integer);
begin
If CompareText(EventName, 'Item_Category_Upd') = 0 Then
tbItems.Refresh;
end;
It's working fine, but the event is called locally and also on all clients.

Related

How can I implement this functionality with Supabase?

I'm working on a web application. Vue + Supabase.
There are two registration forms in the application. One is for regular users, the other is for special users.
Regular users can easily register, but special users must enter a special code that is generated in the admin panel, when admin click on the "add code" button, and this code must be deleted after successful registration.
How can such functionality be implemented? Deleting the code after registration is understandable - a simple trigger, adding - a simple check for the admin role (row policy). But how to implement check at registration??
In principle, there will be few users and none of them will try to hack the application, but still I don't want to make a filter at the front. Something like:
supabase
.from('verif_codes')
.select('*')
.eq('code', this.userEnteredCode)
.then(res => {
if (res.data.length === 0){
this.errors.code = true;
} else {
supabase.singUp(...)
}
});
Thanks!!
The supabase.signUp() call inserts a new row in the auth.users table if it is successful. This means that you can implement what you want in a trigger attached to the auth.users table.
For example:
You can pass the code to the options.data parameter of the supabase.signUp method
The data inside the options.data parameter is stored in the raw_user_meta_data column of the auth.users table
Given (1) and (2) above, you can create a BEFORE INSERT trigger on the auth.users table and check that the code (which can be accessed like this: NEW.raw_user_meta_data->>'myCodeField') actually exists in the table where you store your codes (which should still be protected using RLS or some other mechanism to ensure that no one can tamper with them)
If the code does NOT exist, you can abort the insertion (which would essentially abort the registration) by throwing an exception (e.g. with RAISE EXCEPTION) or just returning NULL from the trigger function

How do I do conditional check, return error, or continue?

A user wants to invite a friend but I want to do a check first. For example:
SELECT friends_email from invites where friends_email = $1 limit 1;
If that finds one then I want to return a message such as "This friend already invited."
If that does not find one then I want to do an insert
INSERT INTO invites etc...
but then I need to return the primary user's region_id
SELECT region_id from users where user_id = $2
What's the best way to do this?
Thanks.
EDIT --------------------------------------------------------------
After many hours below is what I ended up with in 'plpgsql'.
IF EXISTS (SELECT * FROM invitations WHERE email = friends_email) THEN
return 'Already Invited';
END IF;
INSERT INTO invitations (email) VALUES (friends_email);
return 'Invited';
I undestand that there are probably dozens of better ways but this worked for me.
Without writing the exact code snippet for you...
Consider solving this problem by shaping your data to conform to your business rules. If you can only invite someone once, then you should have an "invites" table that reflects this by a UNIQUE rule across whatever columns define a unique invite. If it is just an email address, then declare the "invites.email" as a unique column.
Then do an INSERT. Write the insert so that it takes advantage of Postgres' RETURNING clause to give an answer on success. If the INSERT fails (because you already have that email address -- which was the point of the check you wanted to do), then catch the failure in your application code, and return the appropriate response.
Psuedocode:
Application:
try
invite.insert(NewGuy)
catch error.UniqueFail
return "He's already been invited"
# ...do other stuff
Postgres:
INSERT INTO invites
(data fields + SELECT region thingy)
VALUES
(some arrangement of data that includes "region_id")
RETURNING region_id
If that's hard to make work the first time you try it, phrasing the insert target as a CTE may be helpful. If all else fails, write it procedurally in plpgsql for the time being, making sure the external interface accepts a normal INSERT (so you don't have to change application code later) and sort it out once you know whether or not performance is an issue.
The basic idea here is to let the relational shape of your data obviate the need for any procedural checking wherever you can. That's at the heart of relational data modeling ...somewhat of a lost art these days.
You can create SQL stored procedure for implement functionality like described above.
But it is wrong form architecture point of view. See: Direct database manipulation an anti-pattern?
DB have scope of responsibility: store data.
You have to put business logic into your business layer.

How To Save A Value from TextBox In MS Access 2010

Good day,
In my Ms Access 2010 Form, I have 4 textboxes, namely GrossAmt, WTax1, WTax2, and NetAmt.
GrossAmt, WTax1, and WTax2 are bounded. And so, their values are stored in the table.
NetAmt is unbounded as I have a function running. In its Control Source I have this:
=[GrossAmount]-([WTax1]+[WTax2]).
which is running properly. My problem is, how can I save the value(answer) in the table?
I have tried adding another textbox (named NetAmount) which is bounded to the table and was supposed to copy the values from the unbounded textbox. I have tried putting Me.NetAmount = Me.NetAmt in the "After Update" Event in Property but its not saving.
What should I do, I don't have any clue on what to do anymore. Thank you for your help.
with the equals sign, the value is not stored anywhere, it is calculated on the fly.
If GrosssAmount, WTax1 & WTax2 are stored in the database you never need to store that data, instead you can run the calculation based on the other three. In fact, I would recommend that you do it this way, unless there is a particular need to retrieve a historic net amount.
If you wanted to save the data to the database, you're going to have to use code on Update.
the easiest would be to write a function, something like
Private Function saveNetAmount()
Me.[NetAmount] = [GrossAmount]-([WTax1]+[WTax2])
End Function
and then add that into the AfterUpdate or OnChange event for the Gross Amount, WTax1 and WTax2 text boxes.
Something like:
Private Sub GrossAmt_AfterUpdate()
Call saveNetAmount
End Sub

Oracle Forms 10g - why do I have to click save so that my insert query will save to database

why do i have to click save button in the upperleft on formservlet so that my insert query will save to database? im sorry guys, quite newbie here thanks
here is my pl sql code in add button trigger:
begin
insert into tb_distributor
(distributor_id, distributor_name, distributor_type, distributor_desc)
values
(distributor_id.nextval,:DISTRIBUTOR_NAME, :DISTRIBUTOR_TYPE, :DISTRIBUTOR_DESC);
commit;
end;
Oracle Forms provides a great deal of functionality for you so that you don't have to write it. For example, if you base a block on a table, and if the user enters data and clicks "Save", Oracle Forms knows whether to execute Insert, Update or Delete statements appropriately followed by a Commit.
In your case, you have ignored that functionality and have hardcoded an Insert and Commit in your button code. Therefore, the user does not have to click the Save button, because the data has already been "saved" by your Add button.
open the property palette for this data block and change the database data block item to NO
and start writing your PL/SQL manually.

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.