-
Notifications
You must be signed in to change notification settings - Fork 6
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
Enable raw arguments in query #51
base: master
Are you sure you want to change the base?
Conversation
'use_raw_arguments' = 1 this way, we can make query with aggregate function(s), datetime functions, etc.
Istina, ovime smo podložni SQL injection-u, te moramo dati funkciju koju baza podržava. Ovo je više bio kao POC - da vidim hoće li raditi, bez mnogo kompliciranja |
@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 |
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();
}
} |
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"
}
] |
Have added a new PR #55 for to solve this use cases. 🥳 |
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
}