Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Enable raw arguments in query #51

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
ngaspari wants to merge 3 commits into master
base: master
Choose a base branch
Loading
from vsliv_enable_raw_arguments

Conversation

@ngaspari
Copy link
Contributor

@ngaspari ngaspari commented Feb 13, 2024

Option to handle request parameters as raw arguments.

For example:
api/search/{model}

{
"search": {
"remote_relations.remote_model_type": "=contact",
"remote_relations.remote_model_id": "=...."
},
"group_by": ["year", "month"],
"order_by": ["year", "month"],
"returns": ["DATE_PART('Year', created_at) AS year", "DATE_PART('Month', created_at) AS month", "COUNT(*) AS total"],
"use_raw_arguments": 1
}

ngaspari and others added 2 commits February 13, 2024 11:16
'use_raw_arguments' = 1
this way, we can make query with aggregate function(s), datetime functions, etc.
Copy link

toni4848 commented Feb 14, 2024
edited
Loading

@ngaspari @izibrat Je li nam pametno stavljati raw SQL upit u request body zbog sigurnosnog rizika, težeg održavanja, vežemo se direktno na bazu - neko limitiranje abstrakcije, a možda i smanjena validacija?

Kod je ok.

@ngaspari možeš li ažurirati dokumentaciju (README) da nam se ne izgubi dorada.

Copy link
Contributor Author

@ngaspari @izibrat Je li nam pametno stavljati raw SQL upit u request body zbog sigurnosnog rizika, težeg održavanja, vežemo se direktno na bazu - neko limitiranje abstrakcije, a možda i smanjena validacija?

Kod je ok.

@ngaspari možeš li ažurirati dokumentaciju (README) da nam se ne izgubi dorada.

Istina, ovime smo podložni SQL injection-u, te moramo dati funkciju koju baza podržava.
Nisam našao neki out-of-the box način da ovo drugačije riješi sa Laravel/Eloquent.
Moguće je to malo apstraktnije složiti, naravno (opet moramo pokrivati različite DB opcije onda).
npr:
"returns": [
['func' => 'YEAR', 'field' => 'created_at', 'as' => 'year'],
['func' => 'MONTH', 'field' => 'created_at', 'as' => 'month'],
['func' => 'COUNT', 'field' => '*', 'as' => 'total'],
],

Ovo je više bio kao POC - da vidim hoće li raditi, bez mnogo kompliciranja

Copy link

nealarec commented Apr 4, 2024

@ngaspari Have found a more interesting whom to do this, I added some code to the returns' preprocessor, will public a pr in a couple of days

Copy link

nealarec commented Apr 4, 2024

You can override the Returns Argument with a custom class implementing this trait

use Asseco\JsonQueryBuilder\Exceptions\JsonQueryBuilderException;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
class PGSQLAggregations {
 public static function year($raw) {
 return "EXTRACT(YEAR FROM $raw)";
 }
 public static function month($raw) {
 return "EXTRACT(MONTH FROM $raw)";
 }
 public static function day($raw) {
 return "EXTRACT(DAY FROM $raw)";
 }
}
trait AggregationTrait {
 public Builder $builder;
 protected array $providers = [
 "pgsql" => PGSQLAggregations::class,
 ];
 protected const DB_FUNCTIONS = [
 "avg",
 "count",
 "max",
 "min",
 "sum",
 "distinct",
 "year",
 "month",
 "day",
 ];
 protected function areArgumentsValid(): void {
 foreach ($this->arguments as $argument) {
 $split = explode(":", $argument);
 if (count($split) == 1) {
 continue;
 }
 $column = array_pop($split);
 if (!preg_match("/^[a-zA-Z_][a-zA-Z0-9_]*|\*$/", $column)) {
 throw new JsonQueryBuilderException(
 "Invalid column name: {$column}."
 );
 }
 if ($invalidFns = array_diff($split, self::DB_FUNCTIONS)) {
 throw new JsonQueryBuilderException(
 "Invalid function: " . join(",", $invalidFns) . "."
 );
 }
 }
 }
 private function applyAggrs(array $params): string {
 $column = array_pop($params);
 $provider =
 $this->builder->getModel()->connection ??
 config("database.default");
 return array_reduce($params, function ($query, $param) use (
 $column,
 $provider
 ) {
 $stat = $query ?? $column;
 if (
 $this->providers[$provider] &&
 method_exists($this->providers[$provider], $param)
 ) {
 return $this->providers[$provider]::$param($stat);
 }
 return "$param($stat)";
 });
 }
 protected function appendQuery(): void {
 $this->arguments = array_map(function ($argument) {
 if (strpos($argument, ":") === false) {
 return $argument;
 }
 $split = explode(":", $argument);
 $apply = $this->applyAggrs($split);
 $alias = join("_", $split);
 return DB::raw("{$apply} as {$alias}");
 }, $this->arguments);
 parent::appendQuery();
 }
}

Copy link

nealarec commented Apr 4, 2024

Example of working query

{
 "search": { "close_date": "<>2024年01月01日;2024年12月31日" },
 "returns": [
 "year:close_date",
 "month:close_date",
 "sum:value",
 "avg:value",
 "count:value",
 "max:year:close_date",
 "min:year:close_date",
 "max:month:close_date",
 "min:month:close_date"
 ],
 "group_by": ["year_close_date", "month_close_date"]
}

Result

[
 {
 "year_close_date": "2024",
 "month_close_date": "3",
 "sum_value": "280990",
 "avg_value": "93663.33333333333",
 "count_value": 3,
 "max_year_close_date": "2024",
 "min_year_close_date": "2024",
 "max_month_close_date": "3",
 "min_month_close_date": "3"
 },
 {
 "year_close_date": "2024",
 "month_close_date": "4",
 "sum_value": "500000",
 "avg_value": "500000",
 "count_value": 1,
 "max_year_close_date": "2024",
 "min_year_close_date": "2024",
 "max_month_close_date": "4",
 "min_month_close_date": "4"
 }
]

Copy link

nealarec commented Apr 4, 2024

Have added a new PR #55 for to solve this use cases. 🥳

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@DevFajdetic DevFajdetic Awaiting requested review from DevFajdetic

@dadeky dadeky Awaiting requested review from dadeky

@marijo-pavlov marijo-pavlov Awaiting requested review from marijo-pavlov

@toni4848 toni4848 Awaiting requested review from toni4848

@DaveXo9 DaveXo9 Awaiting requested review from DaveXo9

At least 1 approving review is required to merge this pull request.

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

AltStyle によって変換されたページ (->オリジナル) /