prisma-client-php 0.0.39 → 0.0.40

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.
@@ -749,105 +749,273 @@ final class PPHPUtility
749
749
  }
750
750
  }
751
751
 
752
+ private static function handleImplicitRelationSelect(
753
+ string $model,
754
+ string $relatedModel,
755
+ string $dbType,
756
+ PDO $pdo,
757
+ mixed $primaryId
758
+ ): array {
759
+ $implicitModelInfo = PPHPUtility::compareStringsAlphabetically($relatedModel, $model);
760
+ $searchColumn = ($relatedModel === $implicitModelInfo['A']) ? 'B' : 'A';
761
+ $tableName = self::quoteColumnName($dbType, $implicitModelInfo['Name']);
762
+ $searchColumnQuoted = self::quoteColumnName($dbType, $searchColumn);
763
+
764
+ $sqlSelect = "SELECT * FROM $tableName WHERE $searchColumnQuoted = ?";
765
+ $stmtSelect = $pdo->prepare($sqlSelect);
766
+ $stmtSelect->execute([$primaryId]);
767
+ return $stmtSelect->fetchAll();
768
+ }
769
+
770
+ private static function handleImplicitRelationInsert(
771
+ string $model,
772
+ string $relatedModel,
773
+ string $dbType,
774
+ PDO $pdo,
775
+ mixed $primaryId,
776
+ mixed $relatedId
777
+ ): array {
778
+ $implicitModelInfo = PPHPUtility::compareStringsAlphabetically($relatedModel, $model);
779
+ $searchColumn = ($relatedModel === $implicitModelInfo['A']) ? 'B' : 'A';
780
+ $returnColumn = ($searchColumn === 'A') ? 'B' : 'A';
781
+
782
+ if ($implicitModelInfo['A'] === $model) {
783
+ $searchColumnValue = $primaryId;
784
+ $returnColumnValue = $relatedId;
785
+ } else {
786
+ $searchColumnValue = $relatedId;
787
+ $returnColumnValue = $primaryId;
788
+ }
789
+
790
+ $tableName = self::quoteColumnName($dbType, $implicitModelInfo['Name']);
791
+ $searchColumnQuoted = self::quoteColumnName($dbType, $searchColumn);
792
+ $returnColumnQuoted = self::quoteColumnName($dbType, $returnColumn);
793
+
794
+ $sql = "INSERT IGNORE INTO $tableName ($searchColumnQuoted, $returnColumnQuoted) VALUES (?, ?)";
795
+ $stmt = $pdo->prepare($sql);
796
+ $stmt->execute([$searchColumnValue, $returnColumnValue]);
797
+
798
+ $sqlSelect = "SELECT * FROM $tableName WHERE $searchColumnQuoted = ? AND $returnColumnQuoted = ?";
799
+ $stmtSelect = $pdo->prepare($sqlSelect);
800
+ $stmtSelect->execute([$searchColumnValue, $returnColumnValue]);
801
+
802
+ $result = $stmtSelect->fetch();
803
+ return $result ?: [];
804
+ }
805
+
806
+ private static function handleImplicitRelationDelete(
807
+ string $model,
808
+ string $relatedModel,
809
+ string $dbType,
810
+ PDO $pdo,
811
+ mixed $primaryId,
812
+ array $allNewRelatedIds
813
+ ): void {
814
+ $implicitModelInfo = PPHPUtility::compareStringsAlphabetically($relatedModel, $model);
815
+ $searchColumn = ($relatedModel === $implicitModelInfo['A']) ? 'B' : 'A';
816
+ $returnColumn = ($searchColumn === 'A') ? 'B' : 'A';
817
+
818
+ $tableName = self::quoteColumnName($dbType, $implicitModelInfo['Name']);
819
+ $searchColumnQuoted = self::quoteColumnName($dbType, $searchColumn);
820
+ $returnColumnQuoted = self::quoteColumnName($dbType, $returnColumn);
821
+
822
+ if (count($allNewRelatedIds) > 0) {
823
+ $placeholders = implode(',', array_fill(0, count($allNewRelatedIds), '?'));
824
+ $sqlDelete = "DELETE FROM $tableName WHERE $searchColumnQuoted = ? AND $returnColumnQuoted NOT IN ($placeholders)";
825
+ $stmtDelete = $pdo->prepare($sqlDelete);
826
+ $stmtDelete->execute(array_merge([$primaryId], $allNewRelatedIds));
827
+ } else {
828
+ $sqlDelete = "DELETE FROM $tableName WHERE $searchColumnQuoted = ?";
829
+ $stmtDelete = $pdo->prepare($sqlDelete);
830
+ $stmtDelete->execute([$primaryId]);
831
+ }
832
+ }
833
+
752
834
  public static function processRelation(
753
- array $relatedField,
835
+ string $modelName,
836
+ string $relatedFieldName,
754
837
  array $fieldData,
755
- array $relationFromFields,
756
- array $relationToFields,
757
- string $relatedClassName,
758
- string $model,
759
838
  PDO $pdo,
760
839
  string $dbType,
761
- string $lastInsertId = '',
762
840
  bool $requestOption = true,
763
841
  ): array {
764
- $fieldName = $relatedField['name'];
765
- if (count($relationFromFields) !== count($relationToFields)) {
766
- throw new Exception("Mismatch between 'relationFromFields' and 'relationToFields' for relation '$fieldName'.");
767
- }
768
842
 
769
- $reflection = new ReflectionClass($relatedClassName);
770
- $relatedClass = $reflection->newInstance($pdo);
843
+ $modelClassName = "Lib\\Prisma\\Classes\\" . $modelName;
844
+ $modelReflection = new ReflectionClass($modelClassName);
845
+ $modelClass = $modelReflection->newInstance($pdo);
846
+ $modelFieldsRelatedWithKeys = $modelClass->_fieldsRelatedWithKeys[$relatedFieldName];
847
+ $modelRelatedFromFields = $modelFieldsRelatedWithKeys['relationFromFields'];
848
+ $modelRelatedToFields = $modelFieldsRelatedWithKeys['relationToFields'];
849
+ $modelRelatedField = $modelClass->_fields[$relatedFieldName];
850
+ $modelRelatedFieldIsList = $modelRelatedField['isList'] ?? false;
851
+ $modelRelatedFieldType = $modelRelatedField['type'];
852
+ $relatedClassName = "Lib\\Prisma\\Classes\\" . $modelRelatedFieldType;
853
+ $relatedReflection = new ReflectionClass($relatedClassName);
854
+ $relatedClass = $relatedReflection->newInstance($pdo);
855
+
771
856
  $relatedResult = null;
857
+ foreach ($fieldData as $action => $actionData) {
858
+ $operations = isset($actionData[0]) ? $actionData : [$actionData];
859
+
860
+ foreach ($operations as $op) {
861
+ switch ($action) {
862
+ case 'connect':
863
+ if (empty($modelRelatedFromFields) && empty($modelRelatedToFields)) {
864
+ $relatedFieldData = $op[$modelRelatedFieldType];
865
+ $modelFieldData = $op[$modelName];
866
+ $relatedResult = self::handleImplicitRelationInsert(
867
+ $modelName,
868
+ $modelRelatedFieldType,
869
+ $dbType,
870
+ $pdo,
871
+ $relatedFieldData[$relatedClass->_primaryKey],
872
+ $modelFieldData[$modelClass->_primaryKey]
873
+ );
874
+ } else {
875
+ if (!$modelRelatedFieldIsList && count($operations) > 1) {
876
+ throw new Exception("Cannot connect multiple records for a non-list relation '$relatedFieldName'.");
877
+ }
772
878
 
773
- if (isset($fieldData['create'])) {
774
- $relatedData = ['data' => $fieldData['create']];
775
- $relatedResult = $relatedClass->create($relatedData);
776
- } elseif (isset($fieldData['connect'])) {
777
- if (empty($relationToFields) && empty($relationFromFields) && !empty($lastInsertId)) {
778
- $relatedDataArray = $fieldData['connect'];
779
- $relatedId = is_array($relatedDataArray) ? reset($relatedDataArray) : $relatedDataArray;
780
- $implicitModelInfo = PPHPUtility::compareStringsAlphabetically($relatedField['type'], $model);
781
- $searchColumn = ($relatedField['type'] === $implicitModelInfo['A']) ? 'B' : 'A';
782
- $returnColumn = ($searchColumn === 'A') ? 'B' : 'A';
783
-
784
- $searchColumnValue = '';
785
- $returnColumnValue = '';
786
- if ($implicitModelInfo['A'] === $model) {
787
- $searchColumnValue = $lastInsertId;
788
- $returnColumnValue = $relatedId;
789
- } else {
790
- $searchColumnValue = $relatedId;
791
- $returnColumnValue = $lastInsertId;
792
- }
879
+ $relatedResult = $relatedClass->findUnique(['where' => $op]);
880
+ }
881
+ break;
882
+ case 'connectOrCreate':
883
+ if (empty($modelRelatedFromFields) && empty($modelRelatedToFields)) {
884
+ $relatedFieldData = $op[$modelRelatedFieldType];
885
+ $modelFieldData = $op[$modelName];
886
+ $existingRecord = $relatedClass->findFirst(['where' => $relatedFieldData['where']]);
887
+
888
+ if ($existingRecord) {
889
+ $record = $existingRecord;
890
+ } else {
891
+ $record = $relatedClass->create(['data' => $relatedFieldData['create']]);
892
+ }
793
893
 
794
- $tableName = self::quoteColumnName($dbType, $implicitModelInfo['Name']);
795
- $searchColumn = self::quoteColumnName($dbType, $searchColumn);
796
- $returnColumn = self::quoteColumnName($dbType, $returnColumn);
797
- $sql = "INSERT IGNORE INTO $tableName ($searchColumn, $returnColumn) VALUES (?,?)";
798
- $stmt = $pdo->prepare($sql);
799
- $stmt->execute([$searchColumnValue, $returnColumnValue]);
800
-
801
- $sqlSelect = "SELECT * FROM $tableName WHERE $searchColumn = ? AND $returnColumn = ?";
802
- $stmtSelect = $pdo->prepare($sqlSelect);
803
- $stmtSelect->execute([$searchColumnValue, $returnColumnValue]);
804
- $relatedResult = $stmtSelect->fetch();
805
- } else {
806
- $relatedData = ['where' => $fieldData['connect']];
807
- $relatedResult = $relatedClass->findUnique($relatedData);
808
- }
809
- } elseif (isset($fieldData['connectOrCreate'])) {
810
- $relatedData = ['where' => $fieldData['connectOrCreate']['where']];
811
- $relatedResult = $relatedClass->findUnique($relatedData);
894
+ $relatedResult = self::handleImplicitRelationInsert(
895
+ $modelName,
896
+ $modelRelatedFieldType,
897
+ $dbType,
898
+ $pdo,
899
+ $record->{$relatedClass->_primaryKey},
900
+ $modelFieldData[$modelClass->_primaryKey]
901
+ );
902
+ } else {
812
903
 
813
- if (!$relatedResult) {
814
- $relatedData = ['data' => $fieldData['connectOrCreate']['create']];
815
- $relatedResult = $relatedClass->create($relatedData);
816
- }
817
- } elseif (isset($fieldData['delete'])) {
818
- $relatedData = ['where' => $fieldData['delete']];
819
- $relatedClass->delete($relatedData);
820
- return [];
821
- } elseif (isset($fieldData['disconnect'])) {
822
- $relatedData = [
823
- 'where' => $fieldData['disconnect'],
824
- 'data' => [
825
- $relationFromFields[0] => null
826
- ]
827
- ];
828
- $relatedResult = $relatedClass->update($relatedData);
829
- } elseif (isset($fieldData['update'])) {
830
- $relatedData = [
831
- 'where' => $fieldData['update']['where'],
832
- 'data' => $fieldData['update']['data']
833
- ];
834
- $relatedResult = $relatedClass->update($relatedData);
835
- } elseif (isset($fieldData['upsert'])) {
836
- $relatedData = ['where' => $fieldData['upsert']['where']];
837
- $relatedResult = $relatedClass->findUnique($relatedData);
838
-
839
- if ($relatedResult) {
840
- $relatedData = [
841
- 'where' => $fieldData['upsert']['where'],
842
- 'data' => $fieldData['upsert']['update']
843
- ];
844
- $relatedResult = $relatedClass->update($relatedData);
845
- } else {
846
- $relatedData = ['data' => $fieldData['upsert']['create']];
847
- $relatedResult = $relatedClass->create($relatedData);
904
+ if (!$modelRelatedFieldIsList && count($operations) > 1) {
905
+ throw new Exception("Cannot connectOrCreate multiple records for a non-list relation '$relatedFieldName'.");
906
+ }
907
+
908
+ $existing = $relatedClass->findUnique(['where' => $op]);
909
+
910
+ if ($existing) {
911
+ $relatedResult = $existing;
912
+ } else {
913
+ $relatedResult = $relatedClass->create(['data' => $op]);
914
+ }
915
+ }
916
+ break;
917
+ case 'create':
918
+ if (empty($modelRelatedFromFields) && empty($modelRelatedToFields)) {
919
+ $relatedFieldData = $op[$modelRelatedFieldType];
920
+ $modelFieldData = $op[$modelName];
921
+ $relatedCreatedData = $relatedClass->create(['data' => $relatedFieldData]);
922
+ $relatedResult = self::handleImplicitRelationInsert(
923
+ $modelName,
924
+ $modelRelatedFieldType,
925
+ $dbType,
926
+ $pdo,
927
+ $relatedCreatedData->{$relatedClass->_primaryKey},
928
+ $modelFieldData[$modelClass->_primaryKey]
929
+ );
930
+ } else {
931
+ if (!$modelRelatedFieldIsList && count($operations) > 1) {
932
+ throw new Exception("Cannot create multiple records for a non-list relation '$relatedFieldName'.");
933
+ }
934
+
935
+ $relatedResult = $relatedClass->create(['data' => $op]);
936
+ }
937
+ break;
938
+ case 'delete':
939
+ $whereCondition = $op[$modelRelatedFieldType];
940
+ $relatedResult = $relatedClass->delete(['where' => $whereCondition]);
941
+ break;
942
+ case 'disconnect':
943
+ if (empty($modelRelatedFromFields) && empty($modelRelatedToFields)) {
944
+ $relatedFieldData = $op[$modelRelatedFieldType];
945
+ $modelFieldData = $op[$modelName];
946
+ $relatedResult = self::handleImplicitRelationDelete(
947
+ $modelName,
948
+ $modelRelatedFieldType,
949
+ $dbType,
950
+ $pdo,
951
+ $modelFieldData[$modelClass->_primaryKey],
952
+ $relatedFieldData[$relatedClass->_primaryKey]
953
+ );
954
+ } else {
955
+ $relatedResult = $relatedClass->delete(['where' => $op]);
956
+ }
957
+ break;
958
+ case 'set':
959
+ if (empty($modelRelatedFromFields) && empty($modelRelatedToFields)) {
960
+ $newRelatedIds = [];
961
+ $primaryId = null;
962
+ foreach ($operations as $opSet) {
963
+ $relatedFieldData = $opSet[$modelRelatedFieldType];
964
+ $modelFieldData = $opSet[$modelName];
965
+ $newRelatedIds[] = $relatedFieldData[$relatedClass->_primaryKey];
966
+ if (!$primaryId) {
967
+ $primaryId = $modelFieldData[$modelClass->_primaryKey];
968
+ }
969
+ }
970
+ $newRelatedIds = array_unique($newRelatedIds);
971
+
972
+ self::handleImplicitRelationDelete(
973
+ $modelName,
974
+ $modelRelatedFieldType,
975
+ $dbType,
976
+ $pdo,
977
+ $primaryId,
978
+ $newRelatedIds
979
+ );
980
+
981
+ foreach ($newRelatedIds as $relatedId) {
982
+ self::handleImplicitRelationInsert(
983
+ $modelName,
984
+ $modelRelatedFieldType,
985
+ $dbType,
986
+ $pdo,
987
+ $relatedId,
988
+ $primaryId
989
+ );
990
+ }
991
+
992
+ $relatedResult = self::handleImplicitRelationSelect(
993
+ $modelName,
994
+ $modelRelatedFieldType,
995
+ $dbType,
996
+ $pdo,
997
+ $primaryId
998
+ );
999
+ } else {
1000
+ $relatedResult = $relatedClass->findUnique(['where' => $op]);
1001
+ }
1002
+ break;
1003
+ case 'update':
1004
+ $relatedFieldData = $op[$modelRelatedFieldType];
1005
+ $relatedResult = $relatedClass->update(['where' => $relatedFieldData['where'], 'data' => $relatedFieldData['data']]);
1006
+ break;
1007
+ case 'upsert':
1008
+ $relatedFieldData = $op[$modelRelatedFieldType];
1009
+ $existing = $relatedClass->findUnique(['where' => $relatedFieldData['where']]);
1010
+
1011
+ if ($existing) {
1012
+ $relatedResult = $relatedClass->update(['where' => $relatedFieldData['where'], 'data' => $relatedFieldData['data']]);
1013
+ } else {
1014
+ $relatedResult = $relatedClass->create(['data' => $op]);
1015
+ }
1016
+ break;
1017
+ }
848
1018
  }
849
- } else {
850
- throw new Exception("No valid action provided for relation '$fieldName'.");
851
1019
  }
852
1020
 
853
1021
  $relatedResult = (array) $relatedResult;
@@ -857,14 +1025,14 @@ final class PPHPUtility
857
1025
  }
858
1026
 
859
1027
  if (!$relatedResult) {
860
- throw new Exception("Failed to process related record for '$fieldName'.");
1028
+ throw new Exception("Failed to process related record for '$relatedFieldName'.");
861
1029
  }
862
1030
 
863
1031
  $bindings = [];
864
- foreach ($relationFromFields as $index => $fromField) {
865
- $toField = $relationToFields[$index];
1032
+ foreach ($modelRelatedFromFields as $index => $fromField) {
1033
+ $toField = $modelRelatedToFields[$index];
866
1034
  if (!isset($relatedResult[$toField])) {
867
- throw new Exception("The field '$toField' is missing in the related data for '$fieldName'.");
1035
+ throw new Exception("The field '$toField' is missing in the related data for '$relatedFieldName'.");
868
1036
  }
869
1037
 
870
1038
  $bindings[$fromField] = $relatedResult[$toField];
@@ -873,38 +1041,6 @@ final class PPHPUtility
873
1041
  return $bindings;
874
1042
  }
875
1043
 
876
- public static function mergeForeignKeysIfNeeded(
877
- array $item,
878
- string $action,
879
- array $relationToFields,
880
- array $relationFromFields,
881
- $lastInsertId,
882
- array $fields
883
- ): array {
884
- foreach ($relationToFields as $idx => $toField) {
885
- if (!array_key_exists($toField, $fields)) {
886
- continue;
887
- }
888
-
889
- $fromField = $relationFromFields[$idx] ?? null;
890
- if (!$fromField) {
891
- continue;
892
- }
893
-
894
- if ($action === 'create') {
895
- $item[$fromField] = $lastInsertId;
896
- } elseif ($action === 'connect') {
897
- $item[$fromField] = $lastInsertId;
898
- } elseif ($action === 'connectOrCreate') {
899
- if (isset($item['where'])) {
900
- $item['where'][$fromField] = $lastInsertId;
901
- }
902
- }
903
- }
904
-
905
- return $item;
906
- }
907
-
908
1044
  public static function populateIncludedRelations(
909
1045
  array $records,
910
1046
  array $includes,
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": "0.0.39",
4
+ "version": "0.0.40",
5
5
  "main": "index.js",
6
6
  "type": "module",
7
7
  "scripts": {