Perl DBIx::Class: select attribute not precluding other fields - sql

I'm trying to use a DBIx::Class ResultSet to build:
SELECT commitment_sub_activity_id, SUM(commitment_amount_in_usd)
FROM query_commitments_financials
GROUP BY (commitment_sub_activity_id)
Here's the Perl code I'm trying to use to do this:
my $sub_activity_commitments = $schema->resultset('QueryCommitmentsFinancial')->search(undef,
{
select => [
'commitment_sub_activity_id',
{ sum => 'commitment_amount_in_usd' }
],
as => [qw/commitment_sub_activity_id total_commitment_in_usd/],
'group_by' => [qw/commitment_sub_activity_id/],
});
As I understand it, the select attribute should prevent any unlisted fields from appearing in the SELECT statement. However, the SQL statement DBIx::Class creates comes out as:
SELECT
me.source_id, me.commitment_id,
me.commitment_obligation_id, me.commitment_sub_activity_id,
me.commitment_task_code, me.commitment_status,
me.commitment_date, me.commitment_currency_id,
me.commitment_amount, me.exchange_rate,
me.commitment_amount_in_usd, me.commitment_sub_activity_id,
SUM( commitment_amount_in_usd )
FROM query_commitments_financials me
GROUP BY commitment_sub_activity_id
This query causes my RDBMS to throw an error because those unexpected columns would all need to be included in the GROUP BY.
What is the correct way to get the DBIx::Class ResultSet to build this aggregate query?
UPDATE: Providing the ResultClass definition of QueryCommitmentsFinancial as requested. I used DBIx::Class::Schema::Loader to create it, so I removed the POD.
use utf8;
package IPMS::Schema::Result::QueryCommitmentsFinancial;
use strict;
use warnings;
use base 'DBIx::Class::Core';
__PACKAGE__->load_components("InflateColumn::DateTime");
__PACKAGE__->table_class("DBIx::Class::ResultSource::View");
__PACKAGE__->table("query_commitments_financials");
__PACKAGE__->add_columns(
"source_id",
{ data_type => "nvarchar", is_nullable => 1, size => 52 },
"commitment_id",
{ data_type => "nvarchar", is_nullable => 1, size => 51 },
"commitment_obligation_id",
{ data_type => "nvarchar", is_nullable => 1, size => 45 },
"commitment_sub_activity_id",
{ data_type => "integer", is_nullable => 0 },
"commitment_task_code",
{ data_type => "nchar", is_nullable => 0, size => 7 },
"commitment_status",
{ data_type => "nvarchar", is_nullable => 0, size => 10 },
"commitment_date",
{ data_type => "datetime", is_nullable => 1 },
"commitment_currency_id",
{ data_type => "integer", is_nullable => 0 },
"commitment_amount",
{ data_type => "money", is_nullable => 1 },
"exchange_rate",
{ data_type => "double precision", is_nullable => 1 },
"commitment_amount_in_usd",
{ data_type => "money", is_nullable => 1 },
);
1;

Related

preference settings api mercadopago

I am having great difficulty in making a payment preference in requecission of the paid market.
$pagamento = $mp->setPreferencia
"items" => [
[
"picture_url" => "https://i.imgur.com/FlFgLr5.jpeg",
"title" => "Saldo #smsgobr",
"description" => "Saldo para o bot #smsgobr no Telegram",
"quantity" => 1,
"currency_id" => "BRL",
"unit_price" => (float)$valor
],
"external_reference" => $hash,
"expiration_date_to" => date ('c', strtotime('+1 day'))
],
[
"payment_methods" => array (
"excluded_payment_types" => array (
"id" => "ticket",
"id" => "bank_transfer",
"id" => "atm",
"id" => "debit_card",
"id" => "account_money"
]);
thank you very much in advance

Call a controller with json data on api plateform

I have build my Application with make:entity,
After I create a query who link all the table to get what I want ( a bit of all tables )
My query is working but now I want to use API Plateform to handling routes.
But I find no way to call my controller with API Plateform notation.
Annotation on Caractéristiques entity.
#[ApiResource(collectionOperations: ['requete' => [
'method' => 'get',
'path' => '/requete',
'controller' => ApiRequeteController::class,
'openapi_context' => [
'summary' => 'get requete',
'requestBody' => [
'content' => [
'application/json' => [
'schema' => [
'type' => 'object',
'properties' =>
[
'montant' => ['type' => 'int'],
'loc' => ['type' => 'string'],
'stat' => ['type' => 'string'],
'type' => ['type' => 'string'],
'sect' => ['type' => 'string'],
],
],
'example' => [
'montant' => 1000000,
'loc' => "test",
'stat' => "test",
'type' => "test",
'sect' => "test",
],
],
],
],
],
],
])]
I have found this way but not working.
give me:
syntax error, unexpected '=>' (T_DOUBLE_ARROW)
on
'method' => 'get',
Any way to do this ?
With POST and another writing
* collectionOperations= {"requete" = {
* "method" = "POST",
* "path" = "/requete",
* "controller" = App\Controller\ApiRequeteController::class,
* "openapi_context" = {
* "summary" = "get requete",
* "requestBody" = {
* "content" = {
* "application/json" = {
* "schema" = {
* "type" = "object",
* "properties" =
* {
* "montant" = {"type" = "int"},
* "loc" = {"type" = "string"},
* "stat" = {"type" = "string"},
* "type" = {"type" = "string"},
* "sect" = {"type" = "string"},
* },
* },
* "example" = {
* "montant" = 1000000,
* "loc" = "test",
* "stat" = "test",
* "type" = "test",
* "sect" = "test",
* },
* },
* },
* },
* }
* }
* }
* )
*/

Laravel 8 - firstOrCreate() doesn't return Default value set in the DB

My MySQL DB has a default value set to 0 for field formed_id:
`former_id` bigint(20) NOT NULL DEFAULT 0
When I use firstOrCreate() method to insert a new record, I do not set formed_id:
$record = Record::firstOrCreate(
[
"name" => "myName",
"nick" => "myNick",
]
);
and the output returns:
{
"id": 10,
"name" => "myName",
"nick => "myNick",
"created_at" => "2020-10-01 00:00:00",
"updated_at" => "2020-10-01 00:00:00",
}
do not contains the former_id field set as default, 0.
To get all fileds in the output model, I need to perform a second query:
$record = Record::firstOrCreate(
[
"name" => "myName",
"nick => "myNick",
]
);
$fullRecord = Record::find($record->id)
in this case the output returns correctly:
{
"id": 10,
"name" => "myName",
"nick => "myNick",
"former_id" => 0,
"created_at" => "2020-10-01 00:00:00",
"updated_at" => "2020-10-01 00:00:00",
}
I do not like this solution because I need to perform two queries instead of one; is there a way to get all fields directly from the firstOrCreate() insert?
Thank you.
Reading the #dave solution:
Laravel 8 - firstOrCreate() doesn't return Default value set in the DB
the final code should be:
$record = Record::firstOrCreate(
[
"name" => "myName",
"nick" => "myNick",
]
);
if ($record->wasRecentlyCreated) {
$record->refresh();
}
This is indeed correct behaviour. It could be highly inefficient by default to fetch a model directly after it has been created.
In your case you could add an $attributes property to your model to achieve default properties and prevent having to do another query.
/**
* The model's attributes.
*
* #var array
*/
protected $attributes = [
'former_id' => 0,
];

How to Alias one of the table sql in cakephp 3.6.3

I'm trying to access Contacts. I'm getting below error
Error: SQLSTATE[42000]: Syntax error or access violation: 1066 Not unique table/alias: 'Contacts'
If you are using SQL keywords as table column names, you can enable identifier quoting for your database connection in config/app.php.
Check SQL Query Screenshot
How do I setAlias() in table associations ?
ContactsController.php
public function index()
{
$this->paginate = [
'contain' => ['Users', 'Contacts', 'SourceProspects', 'Status',
'Secteurs', 'Products']
];
$contacts = $this->paginate($this->Contacts);
$this->set(compact('contacts'));
}
public function view($id = null)
{
$contact = $this->Contacts->get($id, [
'contain' => ['Users', 'Contacts', 'SourceProspects', 'Status',
'Secteurs', 'Products', 'Leads', 'Accounts']
]);
$this->set('contact', $contact);
}
ContactsTable.php
$this->setTable('contacts');
$this->setDisplayField('name');
$this->setPrimaryKey('id');
$this->addBehavior('Timestamp');
$this->belongsTo('Users', [
'foreignKey' => 'user_id'
]);
$this->belongsTo('Contacts', [
'foreignKey' => 'contact_type_id'
]);
$this->belongsTo('Leads', [
'foreignKey' => 'lead_id'
]);
$this->belongsTo('SourceProspects', [
'foreignKey' => 'source_prospect_id'
]);
$this->belongsTo('Accounts', [
'foreignKey' => 'account_id'
]);
$this->belongsTo('Status', [
'foreignKey' => 'statut_id'
]);
$this->belongsTo('Secteurs', [
'foreignKey' => 'secteur_id'
]);
$this->belongsTo('Products', [
'foreignKey' => 'product_id'
]);
$this->hasMany('Accounts', [
'foreignKey' => 'contact_id'
]);
$this->hasMany('Leads', [
'foreignKey' => 'contact_id'
]);
}
The problem seems to be in ContractsTable here
$this->belongsTo('Contacts', [
'foreignKey' => 'contact_type_id'
]);
in this way cake join the Contacts table with itself so creating a non unique alias
maybe is just a typo and you wanted to do
$this->belongsTo('ContactTypes', [
'foreignKey' => 'contact_type_id'
]);
but if you actually want to use that relationship then you have to alias the joined Contacts table
$this->belongsTo('ParentContacts', [ // choose your alias here
'className' => 'Contacts'
'foreignKey' => 'contact_type_id'
]);
so every time you have to refer to the joined table you can do something like
'contain' => [
...,
'ParentContacts',
],

DBIx::Class -- creating unique rows in sub-table

My (simplified) SQLite tables are like this:
create table customers (
id integer primary key autoincrement,
contact_name text,
billaddr_id integer references addresses(id)
);
create table addresses (
id integer primary key autoincrement,
address text
);
And here are the result classes (generated from the sql by dbicdump):
Test::DB::Schema::Result::Customer->table("customers");
Test::DB::Schema::Result::Customer->add_columns(
"id",
{ data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
"contact_name",
{ data_type => "text", is_nullable => 1 },
"billaddr_id",
{ data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
);
Test::DB::Schema::Result::Customer->set_primary_key("id");
Test::DB::Schema::Result::Address->table("addresses");
Test::DB::Schema::Result::Address->add_columns(
"id", { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
"address", { data_type => "text", is_nullable => 1 },
);
Test::DB::Schema::Result::Address->set_primary_key("id");
Test::DB::Schema::Result::Address->has_many(
"customers",
"Test::DB::Schema::Result::Customer",
{ "foreign.billaddr_id" => "self.id" },
{ cascade_copy => 0, cascade_delete => 0 },
);
Test::DB::Schema::Result::Customer->belongs_to(
"billaddr",
"Test::DB::Schema::Result::Address",
{ id => "billaddr_id" },
{
is_deferrable => 0,
join_type => "LEFT",
on_delete => "NO ACTION",
on_update => "NO ACTION",
},
);
This bit of code:
my $data = {
contact_name => 'Jim Customer',
billaddr => {
address => 'Address...',
},
};
my $newcustomer = $c->schema->resultset('Customer')->create($data);
results in this database update:
SELECT me.id, me.address FROM addresses me WHERE ( ( me.address = ? ) ): 'Address...'
BEGIN WORK
SELECT me.id, me.address FROM addresses me WHERE ( ( me.address = ? ) ): 'Address...'
INSERT INTO addresses ( address ) VALUES ( ? ): 'Address...'
INSERT INTO partners ( billaddr_id, contact_name ) VALUES ( ?, ? ) : '10', 'Jim Customer'
COMMIT
Why does it do a select before the insert? Because it's checking to see if an address with the same value of the 'address' column already exists. If it does exist, the ID of that address is reused, like this:
SELECT me.id, me.address FROM addresses me WHERE ( ( me.address = ? ) ): 'Address...'
INSERT INTO partners ( billaddr_id, contact_name ) VALUES ( ?, ? ): '10', 'Another Customer with the same address'
But that's not what I want! I want separate addresses for separate customers, even if they happen to live in the same place at the moment.
How can I make DBIx::Class create a new row in the addresses table every time?
Thanks to abraxxa's comments, I've been pointed in the right direction and have done more reading and testing with DBIx::Class:Schema.
Generating the table from the Schema classes, rather than the other way round, seems like the way to go, especially if it will make future upgrades to the database easier.
I've boiled the problem down to the following example code:
Test.pl:
#!/usr/bin/perl
use Test::DB::Schema;
my $schema = Test::DB::Schema->connect(
"dbi:SQLite:dbname=dbicsl_test.db", '', '', {}
);
$schema->deploy({ add_drop_table => 1 } , '.');
$schema->storage->debug(1);
my $data1 = {
text => 'Fred',
table2 => {
text => 'abc',
}
};
my $new1 = $schema->resultset('Table1')->create($data1);
my $data2 = {
text => 'Jim',
table2 => {
text => 'xyz',
}
};
my $new2 = $schema->resultset('Table1')->create($data2);
my $data3 = {
text => 'Emily',
table2 => {
text => 'abc',
}
};
my $new3 = $schema->resultset('Table1')->create($data3);
Test::DB::Schema::Result::Table1.pm:
package Test::DB::Schema::Result::Table1;
use base 'DBIx::Class::Core';
__PACKAGE__->table("table1");
__PACKAGE__->add_columns(
"id",
{ data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
"text",
{ data_type => "text", is_nullable => 1 },
"table2_id",
{ data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
);
__PACKAGE__->set_primary_key("id");
__PACKAGE__->has_one(
table2 =>
"Test::DB::Schema::Result::Table2",
{ 'foreign.id' => 'self.table2_id' },
);
1;
Test::DB::Schema::Result::Table2:
package Test::DB::Schema::Result::Table2;
use base 'DBIx::Class::Core';
__PACKAGE__->table("table2");
__PACKAGE__->add_columns(
"id",
{ data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
"text",
{ data_type => "text", is_nullable => 0 },
);
__PACKAGE__->set_primary_key("id");
1;
And here's the output:
SELECT me.id, me.text FROM table2 me WHERE ( me.text = ? ): 'abc'
BEGIN WORK
SELECT me.id, me.text FROM table2 me WHERE ( me.text = ? ): 'abc'
INSERT INTO table2 ( text) VALUES ( ? ): 'abc'
INSERT INTO table1 ( table2_id, text) VALUES ( ?, ? ): '1', 'Fred'
COMMIT
SELECT me.id, me.text FROM table2 me WHERE ( me.text = ? ): 'xyz'
BEGIN WORK
SELECT me.id, me.text FROM table2 me WHERE ( me.text = ? ): 'xyz'
INSERT INTO table2 ( text) VALUES ( ? ): 'xyz'
INSERT INTO table1 ( table2_id, text) VALUES ( ?, ? ): '2', 'Jim'
COMMIT
SELECT me.id, me.text FROM table2 me WHERE ( me.text = ? ): 'abc'
INSERT INTO table1 ( table2_id, text) VALUES ( ?, ? ): '1', 'Emily'
So the database now looks like
table1.id table1.text table1.table2_id
1 Fred 1
2 Jim 2
3 Emily 1
table2.id table2.text
1 abc
2 xyz
whereas I expected / hoped for:
table1.id table1.text table1.table2_id
1 Fred 1
2 Jim 2
3 Emily 3
table2.id table2.text
1 abc
2 xyz
3 abc
Why does it reuse 1/abc when I haven't told it to make the table2.text column unique?