prisma-client-php 2.0.11 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/init.js CHANGED
@@ -163,7 +163,8 @@ async function installComposerDependencies(isPrismaPHP) {
163
163
  composerDependencies.push(
164
164
  composerPkg("ezyang/htmlpurifier"),
165
165
  composerPkg("symfony/uid"),
166
- composerPkg("brick/math")
166
+ composerPkg("brick/math"),
167
+ composerPkg("tsnc/prisma-php")
167
168
  );
168
169
  }
169
170
  try {
@@ -203,6 +204,7 @@ const composerPinnedVersions = {
203
204
  "calicastle/cuid": "^2.0.0",
204
205
  "symfony/uid": "^7.2.0",
205
206
  "brick/math": "^0.13.1",
207
+ "tsnc/prisma-php": "^1.0.0",
206
208
  };
207
209
  function composerPkg(name) {
208
210
  return composerPinnedVersions[name]
@@ -2,7 +2,7 @@
2
2
 
3
3
  namespace Lib\Prisma\Classes;
4
4
 
5
- use Lib\Validator;
5
+ use PPHP\Validator;
6
6
  use ReflectionClass;
7
7
  use Exception;
8
8
  use PDO;
@@ -476,107 +476,93 @@ final class PPHPUtility
476
476
  }
477
477
  }
478
478
 
479
- /**
480
- * Modifies the given SQL query based on the provided criteria.
481
- *
482
- * This function handles the following criteria:
483
- * - _max: Adds MAX() aggregate functions for specified columns.
484
- * - _min: Adds MIN() aggregate functions for specified columns.
485
- * - _count: Adds COUNT() aggregate functions for specified columns.
486
- * - _avg: Adds AVG() aggregate functions for specified columns.
487
- * - _sum: Adds SUM() aggregate functions for specified columns.
488
- * - orderBy: Adds ORDER BY clause based on specified columns and directions.
489
- * - take: Adds LIMIT clause to restrict the number of rows returned.
490
- * - skip: Adds OFFSET clause to skip a specified number of rows.
491
- *
492
- * @param array $criteria An associative array of criteria for modifying the query.
493
- * @param string &$sql The SQL query string to be modified.
494
- * @param string $dbType The type of the database (e.g., 'mysql', 'pgsql').
495
- * @param string $tableName The name of the table being queried.
496
- */
497
- public static function queryOptions(array $criteria, string &$sql, $dbType, $tableName)
498
- {
499
- // Handle _max, _min, _count, _avg, and _sum
500
- $selectParts = [];
501
- if (isset($criteria['_max'])) {
502
- foreach ($criteria['_max'] as $column => $enabled) {
503
- if ($enabled) {
504
- $selectParts[] = "MAX($tableName." . self::quoteColumnName($dbType, $column) . ") AS max_$column";
505
- }
506
- }
507
- }
508
- if (isset($criteria['_min'])) {
509
- foreach ($criteria['_min'] as $column => $enabled) {
510
- if ($enabled) {
511
- $selectParts[] = "MIN($tableName." . self::quoteColumnName($dbType, $column) . ") AS min_$column";
512
- }
513
- }
514
- }
515
- if (isset($criteria['_count'])) {
516
- foreach ($criteria['_count'] as $column => $enabled) {
517
- if ($enabled) {
518
- $selectParts[] = "COUNT($tableName." . self::quoteColumnName($dbType, $column) . ") AS count_$column";
519
- }
520
- }
521
- }
522
- if (isset($criteria['_avg'])) {
523
- foreach ($criteria['_avg'] as $column => $enabled) {
524
- if ($enabled) {
525
- $selectParts[] = "AVG($tableName." . self::quoteColumnName($dbType, $column) . ") AS avg_$column";
526
- }
527
- }
528
- }
529
- if (isset($criteria['_sum'])) {
530
- foreach ($criteria['_sum'] as $column => $enabled) {
531
- if ($enabled) {
532
- $selectParts[] = "SUM($tableName." . self::quoteColumnName($dbType, $column) . ") AS sum_$column";
479
+ public static function queryOptions(
480
+ array $criteria,
481
+ string &$sql,
482
+ string $dbType,
483
+ string $tableName,
484
+ bool $addAggregates = true
485
+ ): void {
486
+
487
+ if ($addAggregates) {
488
+ $selectParts = [];
489
+
490
+ foreach (
491
+ [
492
+ '_max' => 'MAX',
493
+ '_min' => 'MIN',
494
+ '_count' => 'COUNT',
495
+ '_avg' => 'AVG',
496
+ '_sum' => 'SUM'
497
+ ] as $key => $func
498
+ ) {
499
+
500
+ if (!isset($criteria[$key])) continue;
501
+
502
+ foreach ($criteria[$key] as $col => $enabled) {
503
+ if (!$enabled) continue;
504
+ $alias = strtolower(substr($key, 1)) . "_$col";
505
+ $quoted = self::quoteColumnName($dbType, $col);
506
+ $selectParts[] = "$func($tableName.$quoted) AS $alias";
533
507
  }
534
508
  }
535
- }
536
509
 
537
- // Prepend to SELECT if _max, _min, _count, _avg, or _sum is specified
538
- if (!empty($selectParts)) {
539
- $sql = str_replace('SELECT', 'SELECT ' . implode(', ', $selectParts) . ',', $sql);
510
+ if ($selectParts) {
511
+ $sql = str_replace(
512
+ 'SELECT',
513
+ 'SELECT ' . implode(', ', $selectParts) . ',',
514
+ $sql
515
+ );
516
+ }
540
517
  }
541
518
 
542
- // Handle ORDER BY
543
519
  if (isset($criteria['orderBy'])) {
544
- $orderByParts = self::parseOrderBy($criteria['orderBy'], $dbType, $tableName);
545
- if (!empty($orderByParts)) {
546
- $sql .= " ORDER BY " . implode(', ', $orderByParts);
520
+ $parts = self::parseOrderBy($criteria['orderBy'], $dbType, $tableName);
521
+ if ($parts) {
522
+ $sql .= ' ORDER BY ' . implode(', ', $parts);
547
523
  }
548
524
  }
549
525
 
550
- // Handle LIMIT (take)
551
526
  if (isset($criteria['take'])) {
552
- $sql .= " LIMIT " . intval($criteria['take']);
527
+ $sql .= ' LIMIT ' . intval($criteria['take']);
553
528
  }
554
-
555
- // Handle OFFSET (skip)
556
529
  if (isset($criteria['skip'])) {
557
- $sql .= " OFFSET " . intval($criteria['skip']);
530
+ $sql .= ' OFFSET ' . intval($criteria['skip']);
558
531
  }
559
532
  }
560
533
 
561
- private static function parseOrderBy(array $orderBy, $dbType, $tableName): array
562
- {
563
- $orderByParts = [];
564
-
565
- foreach ($orderBy as $column => $direction) {
566
- if (is_array($direction)) {
567
- // Handle nested orderBy
568
- foreach ($direction as $nestedColumn => $nestedDirection) {
569
- $nestedDirection = strtolower($nestedDirection) === 'desc' ? 'desc' : 'asc';
570
- $orderByParts[] = self::quoteColumnName($dbType, $column) . "." . self::quoteColumnName($dbType, $nestedColumn) . " $nestedDirection";
534
+ private static function parseOrderBy(
535
+ array $orderBy,
536
+ string $dbType,
537
+ string $tableName
538
+ ): array {
539
+ $aggKeys = ['_count', '_avg', '_sum', '_min', '_max'];
540
+ $parts = [];
541
+
542
+ foreach ($orderBy as $key => $value) {
543
+
544
+ if (in_array($key, $aggKeys, true) && is_array($value)) {
545
+ foreach ($value as $field => $dir) {
546
+ $alias = strtolower(substr($key, 1)) . '_' . $field;
547
+ $quoted = self::quoteColumnName($dbType, $alias);
548
+ $parts[] = $quoted . ' ' . (strtolower($dir) === 'desc' ? 'DESC' : 'ASC');
549
+ }
550
+ continue;
551
+ }
552
+
553
+ if (is_array($value)) {
554
+ foreach ($value as $nested => $dir) {
555
+ $dir = strtolower($dir) === 'desc' ? 'DESC' : 'ASC';
556
+ $parts[] = self::quoteColumnName($dbType, $key) . '.' .
557
+ self::quoteColumnName($dbType, $nested) . " $dir";
571
558
  }
572
559
  } else {
573
- // Handle regular orderBy
574
- $direction = strtolower($direction) === 'desc' ? 'desc' : 'asc';
575
- $orderByParts[] = "$tableName." . self::quoteColumnName($dbType, $column) . " $direction";
560
+ $dir = strtolower($value) === 'desc' ? 'DESC' : 'ASC';
561
+ $parts[] = "$tableName." . self::quoteColumnName($dbType, $key) . " $dir";
576
562
  }
577
563
  }
578
564
 
579
- return $orderByParts;
565
+ return $parts;
580
566
  }
581
567
 
582
568
  /**
@@ -1482,4 +1468,79 @@ final class PPHPUtility
1482
1468
  }
1483
1469
  throw new Exception('Unable to determine ID field for implicit many‑to‑many lookup.');
1484
1470
  }
1471
+
1472
+ public static function sqlOperator(string $op): string
1473
+ {
1474
+ return match ($op) {
1475
+ 'equals', '=' => '=',
1476
+ 'gt' => '>',
1477
+ 'gte' => '>=',
1478
+ 'lt' => '<',
1479
+ 'lte' => '<=',
1480
+ 'not' => '<>',
1481
+ 'in' => 'IN',
1482
+ 'notIn' => 'NOT IN',
1483
+ 'between' => 'BETWEEN',
1484
+ default => throw new Exception("Unsupported operator '$op' in HAVING.")
1485
+ };
1486
+ }
1487
+
1488
+ public static function buildHavingClause(
1489
+ array $having,
1490
+ array $aggMap,
1491
+ string $dbType,
1492
+ array &$bindings
1493
+ ): string {
1494
+ if ($having === []) {
1495
+ return '';
1496
+ }
1497
+
1498
+ $useAlias = $dbType !== 'pgsql';
1499
+ $clauses = [];
1500
+
1501
+ foreach ($having as $aggKey => $fields) {
1502
+ if (!isset($aggMap[$aggKey])) {
1503
+ throw new Exception("Unknown aggregate '$aggKey' in 'having'.");
1504
+ }
1505
+ $sqlFunc = $aggMap[$aggKey];
1506
+
1507
+ foreach ($fields as $field => $comparators) {
1508
+ $alias = strtolower(substr($aggKey, 1)) . '_' . $field;
1509
+ $qf = self::quoteColumnName($dbType, $field);
1510
+ $expr = $useAlias ? $alias : "$sqlFunc($qf)";
1511
+
1512
+ foreach ($comparators as $op => $value) {
1513
+ $sqlOp = self::sqlOperator($op);
1514
+
1515
+ if ($sqlOp === 'BETWEEN') {
1516
+ if (!is_array($value) || count($value) !== 2) {
1517
+ throw new Exception("Operator 'between' expects exactly two values for '$alias'.");
1518
+ }
1519
+ $p1 = ':h' . count($bindings) . 'a';
1520
+ $p2 = ':h' . count($bindings) . 'b';
1521
+ $bindings[$p1] = $value[0];
1522
+ $bindings[$p2] = $value[1];
1523
+ $clauses[] = "$expr BETWEEN $p1 AND $p2";
1524
+ } elseif (in_array($sqlOp, ['IN', 'NOT IN'], true)) {
1525
+ if (!is_array($value) || $value === []) {
1526
+ throw new Exception("Operator '$op' expects a non-empty array for '$alias'.");
1527
+ }
1528
+ $phs = [];
1529
+ foreach ($value as $v) {
1530
+ $p = ':h' . count($bindings);
1531
+ $bindings[$p] = $v;
1532
+ $phs[] = $p;
1533
+ }
1534
+ $clauses[] = "$expr $sqlOp (" . implode(', ', $phs) . ')';
1535
+ } else {
1536
+ $p = ':h' . count($bindings);
1537
+ $bindings[$p] = $value;
1538
+ $clauses[] = "$expr $sqlOp $p";
1539
+ }
1540
+ }
1541
+ }
1542
+ }
1543
+
1544
+ return $clauses ? ' HAVING ' . implode(' AND ', $clauses) : '';
1545
+ }
1485
1546
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "prisma-client-php",
3
3
  "description": "Prisma Client PHP is an auto-generated query builder that enables type-safe database access in PHP.",
4
- "version": "2.0.11",
4
+ "version": "2.1.0",
5
5
  "main": "index.js",
6
6
  "type": "module",
7
7
  "scripts": {