prisma-client-php 2.3.6 → 3.0.1
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/generate.js +1 -57
- package/dist/index.enc +1 -1
- package/dist/index.js +1 -44
- package/dist/init.js +1 -240
- package/dist/src/Lib/Prisma/Classes/PPHPUtility.php +277 -60
- package/dist/utils.js +1 -13
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
namespace Lib\Prisma\Classes;
|
|
4
4
|
|
|
5
|
-
use
|
|
5
|
+
use PP\Validator;
|
|
6
6
|
use ReflectionClass;
|
|
7
7
|
use Exception;
|
|
8
8
|
use PDO;
|
|
@@ -122,8 +122,21 @@ final class PPHPUtility
|
|
|
122
122
|
public static function checkFieldsExist(array $select, array $fields, string $modelName)
|
|
123
123
|
{
|
|
124
124
|
$virtualFields = ['_count', '_max', '_min', '_avg', '_sum'];
|
|
125
|
+
$logicKeys = ['AND', 'OR', 'NOT'];
|
|
125
126
|
|
|
126
127
|
foreach ($select as $key => $value) {
|
|
128
|
+
|
|
129
|
+
if (is_string($key) && in_array($key, $logicKeys, true)) {
|
|
130
|
+
if (is_array($value)) {
|
|
131
|
+
foreach ($value as $sub) {
|
|
132
|
+
if (is_array($sub)) {
|
|
133
|
+
self::checkFieldsExist($sub, $fields, $modelName);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
|
|
127
140
|
if (is_numeric($key) && is_string($value)) {
|
|
128
141
|
if (self::fieldExists($key, $fields))
|
|
129
142
|
throw new Exception("The '$value' is indexed, waiting example: ['$value' => true]");
|
|
@@ -131,29 +144,31 @@ final class PPHPUtility
|
|
|
131
144
|
|
|
132
145
|
if (isset($value) && empty($value) || !is_bool($value)) {
|
|
133
146
|
if (is_string($key) && !self::fieldExists($key, $fields)) {
|
|
134
|
-
if (in_array($key, $virtualFields)) {
|
|
147
|
+
if (in_array($key, $virtualFields, true)) {
|
|
135
148
|
continue;
|
|
136
149
|
}
|
|
137
150
|
throw new Exception("The field '$key' does not exist in the $modelName model.");
|
|
138
151
|
}
|
|
139
152
|
|
|
140
153
|
if (is_array($value) && !empty($value)) {
|
|
141
|
-
$
|
|
154
|
+
if (self::isOperatorArray($value)) {
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
142
157
|
|
|
158
|
+
$isRelatedModel = false;
|
|
143
159
|
foreach ($fields as $field) {
|
|
144
|
-
$isObject
|
|
145
|
-
$fieldName = $field['name'];
|
|
146
|
-
|
|
160
|
+
$isObject = ($field['kind'] ?? null) === 'object';
|
|
161
|
+
$fieldName = $field['name'] ?? null;
|
|
147
162
|
if ($isObject && $fieldName === $key) {
|
|
148
163
|
$isRelatedModel = true;
|
|
164
|
+
break;
|
|
149
165
|
}
|
|
150
166
|
}
|
|
151
|
-
|
|
152
167
|
if ($isRelatedModel) continue;
|
|
153
168
|
|
|
154
169
|
$keys = array_keys($value);
|
|
155
170
|
foreach ($keys as $fieldName) {
|
|
156
|
-
$fieldName = trim($fieldName);
|
|
171
|
+
$fieldName = trim((string)$fieldName);
|
|
157
172
|
if (!self::fieldExists($fieldName, $fields)) {
|
|
158
173
|
throw new Exception("The field '$fieldName' does not exist in the $modelName model.");
|
|
159
174
|
}
|
|
@@ -163,10 +178,10 @@ final class PPHPUtility
|
|
|
163
178
|
continue;
|
|
164
179
|
}
|
|
165
180
|
|
|
166
|
-
foreach (explode(',', $key) as $fieldName) {
|
|
181
|
+
foreach (explode(',', (string)$key) as $fieldName) {
|
|
167
182
|
$fieldName = trim($fieldName);
|
|
168
183
|
if (!self::fieldExists($fieldName, $fields)) {
|
|
169
|
-
if (in_array($fieldName, $virtualFields)) {
|
|
184
|
+
if (in_array($fieldName, $virtualFields, true)) {
|
|
170
185
|
continue;
|
|
171
186
|
}
|
|
172
187
|
throw new Exception("The field '$fieldName' does not exist in the $modelName model.");
|
|
@@ -1010,6 +1025,30 @@ final class PPHPUtility
|
|
|
1010
1025
|
$whereCondition = $op[$modelRelatedFieldType];
|
|
1011
1026
|
$relatedResult = $relatedClass->delete(['where' => $whereCondition]);
|
|
1012
1027
|
break;
|
|
1028
|
+
case 'deleteMany':
|
|
1029
|
+
if ($isExplicitOneToMany) {
|
|
1030
|
+
foreach ($operations as $opDelete) {
|
|
1031
|
+
if (!isset($opDelete['where'])) {
|
|
1032
|
+
throw new Exception("deleteMany requires 'where' for '{$relatedFieldName}'.");
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
$where = $opDelete['where'];
|
|
1036
|
+
|
|
1037
|
+
if (!empty($childFkFields)) {
|
|
1038
|
+
$parentId = $opDelete[$childFkFields[0]] ?? null;
|
|
1039
|
+
if ($parentId !== null) {
|
|
1040
|
+
$where[$childFkFields[0]] = $parentId;
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
$relatedClass->deleteMany(['where' => $where]);
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
return [];
|
|
1048
|
+
} else {
|
|
1049
|
+
throw new Exception("deleteMany is only supported for one-to-many relations.");
|
|
1050
|
+
}
|
|
1051
|
+
break;
|
|
1013
1052
|
case 'disconnect':
|
|
1014
1053
|
if ($isExplicitOneToMany) {
|
|
1015
1054
|
foreach ($operations as $opDisc) {
|
|
@@ -1037,68 +1076,73 @@ final class PPHPUtility
|
|
|
1037
1076
|
break;
|
|
1038
1077
|
case 'set':
|
|
1039
1078
|
if ($isExplicitOneToMany) {
|
|
1079
|
+
if (empty($operations)) {
|
|
1080
|
+
return [];
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1040
1083
|
$parentId = $operations[0][$childFkFields[0]]
|
|
1041
1084
|
?? throw new Exception("Missing parent id in 'set' for '{$relatedFieldName}'.");
|
|
1042
1085
|
|
|
1043
|
-
$
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
}
|
|
1048
|
-
}
|
|
1086
|
+
$newIds = [];
|
|
1087
|
+
$keyFields = [];
|
|
1088
|
+
|
|
1089
|
+
$keyFields = array_merge($keyFields, $childFkFields);
|
|
1049
1090
|
|
|
1050
|
-
$
|
|
1051
|
-
$
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
$
|
|
1091
|
+
foreach ($relatedClass->_fields as $fieldName => $fieldMeta) {
|
|
1092
|
+
$kind = $fieldMeta['kind'] ?? 'scalar';
|
|
1093
|
+
$isReadOnly = $fieldMeta['isReadOnly'] ?? false;
|
|
1094
|
+
|
|
1095
|
+
if ($kind === 'scalar' && $isReadOnly && $fieldName !== 'id') {
|
|
1096
|
+
$keyFields[] = $fieldName;
|
|
1097
|
+
}
|
|
1055
1098
|
}
|
|
1056
1099
|
|
|
1057
|
-
$
|
|
1100
|
+
$keyFields = array_unique($keyFields);
|
|
1058
1101
|
|
|
1059
|
-
$newIds = [];
|
|
1060
1102
|
foreach ($operations as $opSet) {
|
|
1061
|
-
$
|
|
1062
|
-
$fkUpdate = array_fill_keys($childFkFields, $parentId);
|
|
1063
|
-
|
|
1064
|
-
$row = $relatedClass->upsert([
|
|
1065
|
-
'where' => $where,
|
|
1066
|
-
'update' => $fkUpdate,
|
|
1067
|
-
'create' => array_merge($where, $fkUpdate),
|
|
1068
|
-
]);
|
|
1103
|
+
$data = $opSet;
|
|
1069
1104
|
|
|
1070
|
-
$
|
|
1071
|
-
|
|
1105
|
+
$where = [];
|
|
1106
|
+
foreach ($keyFields as $field) {
|
|
1107
|
+
if (isset($data[$field])) {
|
|
1108
|
+
$where[$field] = $data[$field];
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1072
1111
|
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
],
|
|
1077
|
-
]);
|
|
1078
|
-
$relatedResult = (array)$relatedResult;
|
|
1112
|
+
if (empty($where)) {
|
|
1113
|
+
throw new Exception("Cannot determine unique identifier for '{$relatedFieldName}'. No key fields found.");
|
|
1114
|
+
}
|
|
1079
1115
|
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1116
|
+
$existing = $relatedClass->findFirst(['where' => $where]);
|
|
1117
|
+
|
|
1118
|
+
if ($existing) {
|
|
1119
|
+
$relatedClass->update([
|
|
1120
|
+
'where' => ['id' => $existing->id],
|
|
1121
|
+
'data' => $data,
|
|
1122
|
+
]);
|
|
1123
|
+
$newIds[] = $existing->id;
|
|
1124
|
+
} else {
|
|
1125
|
+
$created = $relatedClass->create(['data' => $data]);
|
|
1126
|
+
$newIds[] = $created->id;
|
|
1127
|
+
}
|
|
1085
1128
|
}
|
|
1086
1129
|
|
|
1087
|
-
if ($
|
|
1088
|
-
|
|
1130
|
+
if (!empty($newIds)) {
|
|
1131
|
+
$deleteWhere = [
|
|
1132
|
+
$childFkFields[0] => $parentId,
|
|
1133
|
+
'id' => ['notIn' => $newIds],
|
|
1134
|
+
];
|
|
1135
|
+
} else {
|
|
1136
|
+
$deleteWhere = [$childFkFields[0] => $parentId];
|
|
1089
1137
|
}
|
|
1090
1138
|
|
|
1091
|
-
$
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
if (!isset($relatedResult[$toField])) {
|
|
1095
|
-
throw new Exception("The field '{$toField}' is missing …");
|
|
1096
|
-
}
|
|
1097
|
-
}
|
|
1098
|
-
return $bindings;
|
|
1139
|
+
$relatedClass->deleteMany(['where' => $deleteWhere]);
|
|
1140
|
+
|
|
1141
|
+
return [];
|
|
1099
1142
|
} elseif (empty($modelRelatedFromFields) && empty($modelRelatedToFields)) {
|
|
1100
1143
|
$newRelatedIds = [];
|
|
1101
1144
|
$primaryId = null;
|
|
1145
|
+
|
|
1102
1146
|
foreach ($operations as $opSet) {
|
|
1103
1147
|
$relatedFieldData = $opSet[$modelRelatedFieldType];
|
|
1104
1148
|
$modelFieldData = $opSet[$modelName];
|
|
@@ -1144,16 +1188,189 @@ final class PPHPUtility
|
|
|
1144
1188
|
$relatedFieldData = $op[$modelRelatedFieldType];
|
|
1145
1189
|
$relatedResult = $relatedClass->update(['where' => $relatedFieldData['where'], 'data' => $relatedFieldData['data']]);
|
|
1146
1190
|
break;
|
|
1147
|
-
case '
|
|
1148
|
-
$
|
|
1149
|
-
|
|
1191
|
+
case 'updateMany':
|
|
1192
|
+
if ($isExplicitOneToMany) {
|
|
1193
|
+
if (empty($operations)) {
|
|
1194
|
+
return [];
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
$parentId = $operations[0][$childFkFields[0]] ?? null;
|
|
1198
|
+
if ($parentId === null) {
|
|
1199
|
+
throw new Exception("Missing parent id in 'updateMany' for '{$relatedFieldName}'.");
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
$fieldUpdates = [];
|
|
1203
|
+
$ids = [];
|
|
1150
1204
|
|
|
1151
|
-
|
|
1152
|
-
|
|
1205
|
+
foreach ($operations as $opUpdate) {
|
|
1206
|
+
$where = $opUpdate['where'];
|
|
1207
|
+
$data = $opUpdate['data'];
|
|
1208
|
+
|
|
1209
|
+
$record = $relatedClass->findFirst([
|
|
1210
|
+
'where' => array_merge($where, [$childFkFields[0] => $parentId])
|
|
1211
|
+
]);
|
|
1212
|
+
if (!$record) continue;
|
|
1213
|
+
|
|
1214
|
+
$ids[] = $record->id;
|
|
1215
|
+
|
|
1216
|
+
foreach ($data as $field => $value) {
|
|
1217
|
+
if (!isset($fieldUpdates[$field])) {
|
|
1218
|
+
$fieldUpdates[$field] = [];
|
|
1219
|
+
}
|
|
1220
|
+
$fieldUpdates[$field][$record->id] = $value;
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
if (empty($ids)) {
|
|
1225
|
+
return [];
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
$tableName = PPHPUtility::quoteColumnName($dbType, $relatedClass->_tableName);
|
|
1229
|
+
$idColumn = PPHPUtility::quoteColumnName($dbType, 'id');
|
|
1230
|
+
|
|
1231
|
+
$setClauses = [];
|
|
1232
|
+
$bindings = [];
|
|
1233
|
+
|
|
1234
|
+
foreach ($fieldUpdates as $field => $updates) {
|
|
1235
|
+
$fieldQuoted = PPHPUtility::quoteColumnName($dbType, $field);
|
|
1236
|
+
$caseWhen = "CASE";
|
|
1237
|
+
|
|
1238
|
+
foreach ($updates as $id => $value) {
|
|
1239
|
+
$placeholder = ":upd_{$field}_" . count($bindings);
|
|
1240
|
+
$idPlaceholder = ":id_case_" . count($bindings);
|
|
1241
|
+
$caseWhen .= " WHEN $idColumn = $idPlaceholder THEN $placeholder";
|
|
1242
|
+
$bindings[$idPlaceholder] = $id;
|
|
1243
|
+
$bindings[$placeholder] = $value;
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
$caseWhen .= " ELSE $fieldQuoted END";
|
|
1247
|
+
$setClauses[] = "$fieldQuoted = $caseWhen";
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
$idPlaceholders = [];
|
|
1251
|
+
foreach ($ids as $id) {
|
|
1252
|
+
$placeholder = ":id_" . count($bindings);
|
|
1253
|
+
$idPlaceholders[] = $placeholder;
|
|
1254
|
+
$bindings[$placeholder] = $id;
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
$sql = "UPDATE $tableName SET " . implode(', ', $setClauses) .
|
|
1258
|
+
" WHERE $idColumn IN (" . implode(', ', $idPlaceholders) . ")";
|
|
1259
|
+
|
|
1260
|
+
$stmt = $pdo->prepare($sql);
|
|
1261
|
+
foreach ($bindings as $key => $value) {
|
|
1262
|
+
$stmt->bindValue($key, $value);
|
|
1263
|
+
}
|
|
1264
|
+
$stmt->execute();
|
|
1265
|
+
|
|
1266
|
+
return [];
|
|
1153
1267
|
} else {
|
|
1154
|
-
|
|
1268
|
+
throw new Exception("updateMany is only supported for one-to-many relations.");
|
|
1269
|
+
}
|
|
1270
|
+
break;
|
|
1271
|
+
case 'upsert':
|
|
1272
|
+
if ($isExplicitOneToMany) {
|
|
1273
|
+
if (empty($operations)) {
|
|
1274
|
+
return [];
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
$parentId = $operations[0][$childFkFields[0]] ?? null;
|
|
1278
|
+
if ($parentId === null) {
|
|
1279
|
+
throw new Exception("Missing parent id in 'upsert' for '{$relatedFieldName}'.");
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
$tableName = PPHPUtility::quoteColumnName($dbType, $relatedClass->_tableName);
|
|
1283
|
+
$allFields = [];
|
|
1284
|
+
$values = [];
|
|
1285
|
+
$bindings = [];
|
|
1286
|
+
|
|
1287
|
+
$sampleOp = $operations[0];
|
|
1288
|
+
$createData = $sampleOp['create'];
|
|
1289
|
+
$createData[$childFkFields[0]] = $parentId;
|
|
1290
|
+
$fields = array_keys($createData);
|
|
1291
|
+
|
|
1292
|
+
foreach ($fields as $field) {
|
|
1293
|
+
$allFields[] = PPHPUtility::quoteColumnName($dbType, $field);
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
foreach ($operations as $idx => $opUpsert) {
|
|
1297
|
+
$createData = $opUpsert['create'];
|
|
1298
|
+
$createData[$childFkFields[0]] = $parentId;
|
|
1299
|
+
|
|
1300
|
+
$rowPlaceholders = [];
|
|
1301
|
+
foreach ($fields as $field) {
|
|
1302
|
+
$placeholder = ":v{$idx}_{$field}";
|
|
1303
|
+
$rowPlaceholders[] = $placeholder;
|
|
1304
|
+
$bindings[$placeholder] = $createData[$field] ?? null;
|
|
1305
|
+
}
|
|
1306
|
+
$values[] = '(' . implode(', ', $rowPlaceholders) . ')';
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
if ($dbType === 'mysql') {
|
|
1310
|
+
$updateClauses = [];
|
|
1311
|
+
foreach ($fields as $field) {
|
|
1312
|
+
if ($field !== 'id') {
|
|
1313
|
+
$fieldQuoted = PPHPUtility::quoteColumnName($dbType, $field);
|
|
1314
|
+
$updateClauses[] = "$fieldQuoted = VALUES($fieldQuoted)";
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
$sql = "INSERT INTO $tableName (" . implode(', ', $allFields) . ") VALUES " .
|
|
1319
|
+
implode(', ', $values) .
|
|
1320
|
+
" ON DUPLICATE KEY UPDATE " . implode(', ', $updateClauses);
|
|
1321
|
+
} elseif ($dbType === 'pgsql') {
|
|
1322
|
+
$updateClauses = [];
|
|
1323
|
+
$conflictFields = [];
|
|
1324
|
+
|
|
1325
|
+
foreach ($operations[0]['where'] as $whereField => $whereValue) {
|
|
1326
|
+
$conflictFields[] = PPHPUtility::quoteColumnName($dbType, $whereField);
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
foreach ($fields as $field) {
|
|
1330
|
+
if ($field !== 'id' && !in_array($field, array_keys($operations[0]['where']))) {
|
|
1331
|
+
$fieldQuoted = PPHPUtility::quoteColumnName($dbType, $field);
|
|
1332
|
+
$updateClauses[] = "$fieldQuoted = EXCLUDED.$fieldQuoted";
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
$sql = "INSERT INTO $tableName (" . implode(', ', $allFields) . ") VALUES " .
|
|
1337
|
+
implode(', ', $values) .
|
|
1338
|
+
" ON CONFLICT (" . implode(', ', $conflictFields) . ") DO UPDATE SET " .
|
|
1339
|
+
implode(', ', $updateClauses);
|
|
1340
|
+
} elseif ($dbType === 'sqlite') {
|
|
1341
|
+
$updateClauses = [];
|
|
1342
|
+
$conflictFields = [];
|
|
1343
|
+
|
|
1344
|
+
foreach ($operations[0]['where'] as $whereField => $whereValue) {
|
|
1345
|
+
$conflictFields[] = PPHPUtility::quoteColumnName($dbType, $whereField);
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
foreach ($fields as $field) {
|
|
1349
|
+
if ($field !== 'id' && !in_array($field, array_keys($operations[0]['where']))) {
|
|
1350
|
+
$fieldQuoted = PPHPUtility::quoteColumnName($dbType, $field);
|
|
1351
|
+
$updateClauses[] = "$fieldQuoted = excluded.$fieldQuoted";
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
$sql = "INSERT INTO $tableName (" . implode(', ', $allFields) . ") VALUES " .
|
|
1356
|
+
implode(', ', $values) .
|
|
1357
|
+
" ON CONFLICT (" . implode(', ', $conflictFields) . ") DO UPDATE SET " .
|
|
1358
|
+
implode(', ', $updateClauses);
|
|
1359
|
+
} else {
|
|
1360
|
+
throw new Exception("Unsupported database type: $dbType");
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
$stmt = $pdo->prepare($sql);
|
|
1364
|
+
foreach ($bindings as $key => $value) {
|
|
1365
|
+
$stmt->bindValue($key, $value);
|
|
1366
|
+
}
|
|
1367
|
+
$stmt->execute();
|
|
1368
|
+
|
|
1369
|
+
return [];
|
|
1155
1370
|
}
|
|
1156
1371
|
break;
|
|
1372
|
+
default:
|
|
1373
|
+
throw new Exception("Unsupported operation '$action' for relation '{$relatedFieldName}'.");
|
|
1157
1374
|
}
|
|
1158
1375
|
}
|
|
1159
1376
|
}
|
package/dist/utils.js
CHANGED
|
@@ -1,13 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { dirname } from "path";
|
|
3
|
-
/**
|
|
4
|
-
* Retrieves the file metadata including the filename and directory name.
|
|
5
|
-
*
|
|
6
|
-
* @param importMetaUrl - The URL of the module's import.meta.url.
|
|
7
|
-
* @returns An object containing the filename (`__filename`) and directory name (`__dirname`).
|
|
8
|
-
*/
|
|
9
|
-
export function getFileMeta() {
|
|
10
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
-
const __dirname = dirname(__filename);
|
|
12
|
-
return { __filename, __dirname };
|
|
13
|
-
}
|
|
1
|
+
import{fileURLToPath}from"url";import{dirname}from"path";export function getFileMeta(){const e=fileURLToPath(import.meta.url);return{__filename:e,__dirname:dirname(e)}}
|
package/package.json
CHANGED