@prisma/client-engine-runtime 6.14.0-dev.3 → 6.14.0-dev.30
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/QueryPlan.d.ts +15 -12
- package/dist/UserFacingError.d.ts +1 -0
- package/dist/index.d.mts +29 -14
- package/dist/index.d.ts +29 -14
- package/dist/index.js +461 -141
- package/dist/index.mjs +460 -141
- package/dist/interpreter/QueryInterpreter.d.ts +4 -2
- package/dist/interpreter/in-memory-processing.d.ts +3 -0
- package/dist/interpreter/renderQuery.d.ts +1 -1
- package/dist/raw-json-protocol.d.ts +6 -0
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -269,8 +269,10 @@ function mapValue(value, columnName, resultType, enums) {
|
|
|
269
269
|
return values.map((v, i) => mapValue(v, `${columnName}[${i}]`, resultType.inner, enums));
|
|
270
270
|
}
|
|
271
271
|
case "Object": {
|
|
272
|
-
|
|
273
|
-
|
|
272
|
+
return { $type: "Json", value: safeJsonStringify(value) };
|
|
273
|
+
}
|
|
274
|
+
case "Json": {
|
|
275
|
+
return { $type: "Json", value: `${value}` };
|
|
274
276
|
}
|
|
275
277
|
case "Bytes": {
|
|
276
278
|
if (typeof value === "string" && value.startsWith("\\x")) {
|
|
@@ -291,7 +293,7 @@ function mapValue(value, columnName, resultType, enums) {
|
|
|
291
293
|
}
|
|
292
294
|
const enumValue = enumDef[`${value}`];
|
|
293
295
|
if (enumValue === void 0) {
|
|
294
|
-
throw new DataMapperError(`
|
|
296
|
+
throw new DataMapperError(`Value '${value}' not found in enum '${resultType.inner}'`);
|
|
295
297
|
}
|
|
296
298
|
return enumValue;
|
|
297
299
|
}
|
|
@@ -401,6 +403,16 @@ function rethrowAsUserFacing(error) {
|
|
|
401
403
|
}
|
|
402
404
|
throw new UserFacingError(message, code, { driverAdapterError: error });
|
|
403
405
|
}
|
|
406
|
+
function rethrowAsUserFacingRawError(error) {
|
|
407
|
+
if (!isDriverAdapterError(error)) {
|
|
408
|
+
throw error;
|
|
409
|
+
}
|
|
410
|
+
throw new UserFacingError(
|
|
411
|
+
`Raw query failed. Code: ${error.cause.originalCode ?? "N/A"}. Message: ${error.cause.originalMessage ?? renderErrorMessage(error)}`,
|
|
412
|
+
"P2010",
|
|
413
|
+
{ driverAdapterError: error }
|
|
414
|
+
);
|
|
415
|
+
}
|
|
404
416
|
function getErrorCode(err) {
|
|
405
417
|
switch (err.cause.kind) {
|
|
406
418
|
case "AuthenticationFailed":
|
|
@@ -644,6 +656,97 @@ var ProductGenerator = class {
|
|
|
644
656
|
}
|
|
645
657
|
};
|
|
646
658
|
|
|
659
|
+
// src/interpreter/in-memory-processing.ts
|
|
660
|
+
function processRecords(value, ops) {
|
|
661
|
+
if (value == null) {
|
|
662
|
+
return value;
|
|
663
|
+
}
|
|
664
|
+
if (typeof value === "string") {
|
|
665
|
+
return processRecords(JSON.parse(value), ops);
|
|
666
|
+
}
|
|
667
|
+
if (Array.isArray(value)) {
|
|
668
|
+
return processManyRecords(value, ops);
|
|
669
|
+
}
|
|
670
|
+
return processOneRecord(value, ops);
|
|
671
|
+
}
|
|
672
|
+
function processOneRecord(record, ops) {
|
|
673
|
+
if (ops.pagination) {
|
|
674
|
+
const { skip, take, cursor } = ops.pagination;
|
|
675
|
+
if (skip !== null && skip > 0) {
|
|
676
|
+
return null;
|
|
677
|
+
}
|
|
678
|
+
if (take === 0) {
|
|
679
|
+
return null;
|
|
680
|
+
}
|
|
681
|
+
if (cursor !== null && !doKeysMatch(record, cursor)) {
|
|
682
|
+
return null;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
return processNestedRecords(record, ops.nested);
|
|
686
|
+
}
|
|
687
|
+
function processNestedRecords(record, opsMap) {
|
|
688
|
+
for (const [key, ops] of Object.entries(opsMap)) {
|
|
689
|
+
record[key] = processRecords(record[key], ops);
|
|
690
|
+
}
|
|
691
|
+
return record;
|
|
692
|
+
}
|
|
693
|
+
function processManyRecords(records, ops) {
|
|
694
|
+
if (ops.distinct !== null) {
|
|
695
|
+
const fields = ops.linkingFields !== null ? [...ops.distinct, ...ops.linkingFields] : ops.distinct;
|
|
696
|
+
records = distinctBy(records, fields);
|
|
697
|
+
}
|
|
698
|
+
if (ops.pagination) {
|
|
699
|
+
records = paginate(records, ops.pagination, ops.linkingFields);
|
|
700
|
+
}
|
|
701
|
+
if (ops.reverse) {
|
|
702
|
+
records.reverse();
|
|
703
|
+
}
|
|
704
|
+
if (Object.keys(ops.nested).length === 0) {
|
|
705
|
+
return records;
|
|
706
|
+
}
|
|
707
|
+
return records.map((record) => processNestedRecords(record, ops.nested));
|
|
708
|
+
}
|
|
709
|
+
function distinctBy(records, fields) {
|
|
710
|
+
const seen = /* @__PURE__ */ new Set();
|
|
711
|
+
const result = [];
|
|
712
|
+
for (const record of records) {
|
|
713
|
+
const key = getRecordKey(record, fields);
|
|
714
|
+
if (!seen.has(key)) {
|
|
715
|
+
seen.add(key);
|
|
716
|
+
result.push(record);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
return result;
|
|
720
|
+
}
|
|
721
|
+
function paginate(records, pagination, linkingFields) {
|
|
722
|
+
if (linkingFields === null) {
|
|
723
|
+
return paginateSingleList(records, pagination);
|
|
724
|
+
}
|
|
725
|
+
const groupedByParent = /* @__PURE__ */ new Map();
|
|
726
|
+
for (const record of records) {
|
|
727
|
+
const parentKey = getRecordKey(record, linkingFields);
|
|
728
|
+
if (!groupedByParent.has(parentKey)) {
|
|
729
|
+
groupedByParent.set(parentKey, []);
|
|
730
|
+
}
|
|
731
|
+
groupedByParent.get(parentKey).push(record);
|
|
732
|
+
}
|
|
733
|
+
const groupList = Array.from(groupedByParent.entries());
|
|
734
|
+
groupList.sort(([aId], [bId]) => aId < bId ? -1 : aId > bId ? 1 : 0);
|
|
735
|
+
return groupList.flatMap(([, elems]) => paginateSingleList(elems, pagination));
|
|
736
|
+
}
|
|
737
|
+
function paginateSingleList(list, { cursor, skip, take }) {
|
|
738
|
+
const cursorIndex = cursor !== null ? list.findIndex((item) => doKeysMatch(item, cursor)) : 0;
|
|
739
|
+
if (cursorIndex === -1) {
|
|
740
|
+
return [];
|
|
741
|
+
}
|
|
742
|
+
const start = cursorIndex + (skip ?? 0);
|
|
743
|
+
const end = take !== null ? start + take : list.length;
|
|
744
|
+
return list.slice(start, end);
|
|
745
|
+
}
|
|
746
|
+
function getRecordKey(record, fields) {
|
|
747
|
+
return JSON.stringify(fields.map((field) => record[field]));
|
|
748
|
+
}
|
|
749
|
+
|
|
647
750
|
// src/QueryPlan.ts
|
|
648
751
|
function isPrismaValuePlaceholder(value) {
|
|
649
752
|
return typeof value === "object" && value !== null && value["prisma__type"] === "param";
|
|
@@ -659,17 +762,21 @@ function isPrismaValueBigInt(value) {
|
|
|
659
762
|
}
|
|
660
763
|
|
|
661
764
|
// src/interpreter/renderQuery.ts
|
|
662
|
-
function renderQuery(dbQuery, scope, generators) {
|
|
765
|
+
function renderQuery(dbQuery, scope, generators, maxChunkSize) {
|
|
663
766
|
const queryType = dbQuery.type;
|
|
767
|
+
const params = evaluateParams(dbQuery.params, scope, generators);
|
|
664
768
|
switch (queryType) {
|
|
665
769
|
case "rawSql":
|
|
666
|
-
return renderRawSql(dbQuery.sql, evaluateParams(dbQuery.params, scope, generators));
|
|
667
|
-
case "templateSql":
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
770
|
+
return [renderRawSql(dbQuery.sql, evaluateParams(dbQuery.params, scope, generators))];
|
|
771
|
+
case "templateSql": {
|
|
772
|
+
const chunks = dbQuery.chunkable ? chunkParams(dbQuery.fragments, params, maxChunkSize) : [params];
|
|
773
|
+
return chunks.map((params2) => {
|
|
774
|
+
if (maxChunkSize !== void 0 && params2.length > maxChunkSize) {
|
|
775
|
+
throw new UserFacingError("The query parameter limit supported by your database is exceeded.", "P2029");
|
|
776
|
+
}
|
|
777
|
+
return renderTemplateSql(dbQuery.fragments, dbQuery.placeholderFormat, params2);
|
|
778
|
+
});
|
|
779
|
+
}
|
|
673
780
|
default:
|
|
674
781
|
assertNever(queryType, `Invalid query type`);
|
|
675
782
|
}
|
|
@@ -707,61 +814,36 @@ function evaluateParam(param, scope, generators) {
|
|
|
707
814
|
return value;
|
|
708
815
|
}
|
|
709
816
|
function renderTemplateSql(fragments, placeholderFormat, params) {
|
|
710
|
-
let
|
|
711
|
-
|
|
817
|
+
let sql = "";
|
|
818
|
+
const ctx = { placeholderNumber: 1 };
|
|
712
819
|
const flattenedParams = [];
|
|
713
|
-
const
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
if (paramIndex >= params.length) {
|
|
718
|
-
throw new Error(`Malformed query template. Fragments attempt to read over ${params.length} parameters.`);
|
|
719
|
-
}
|
|
720
|
-
flattenedParams.push(params[paramIndex++]);
|
|
721
|
-
return formatPlaceholder(placeholderFormat, placeholderNumber++);
|
|
722
|
-
case "stringChunk":
|
|
723
|
-
return fragment.chunk;
|
|
724
|
-
case "parameterTuple": {
|
|
725
|
-
if (paramIndex >= params.length) {
|
|
726
|
-
throw new Error(`Malformed query template. Fragments attempt to read over ${params.length} parameters.`);
|
|
727
|
-
}
|
|
728
|
-
const paramValue = params[paramIndex++];
|
|
729
|
-
const paramArray = Array.isArray(paramValue) ? paramValue : [paramValue];
|
|
730
|
-
const placeholders = paramArray.length == 0 ? "NULL" : paramArray.map((value) => {
|
|
731
|
-
flattenedParams.push(value);
|
|
732
|
-
return formatPlaceholder(placeholderFormat, placeholderNumber++);
|
|
733
|
-
}).join(",");
|
|
734
|
-
return `(${placeholders})`;
|
|
735
|
-
}
|
|
736
|
-
case "parameterTupleList": {
|
|
737
|
-
if (paramIndex >= params.length) {
|
|
738
|
-
throw new Error(`Malformed query template. Fragments attempt to read over ${params.length} parameters.`);
|
|
739
|
-
}
|
|
740
|
-
const paramValue = params[paramIndex++];
|
|
741
|
-
if (!Array.isArray(paramValue)) {
|
|
742
|
-
throw new Error(`Malformed query template. Tuple list expected.`);
|
|
743
|
-
}
|
|
744
|
-
if (paramValue.length === 0) {
|
|
745
|
-
throw new Error(`Malformed query template. Tuple list cannot be empty.`);
|
|
746
|
-
}
|
|
747
|
-
const tupleList = paramValue.map((tuple) => {
|
|
748
|
-
if (!Array.isArray(tuple)) {
|
|
749
|
-
throw new Error(`Malformed query template. Tuple expected.`);
|
|
750
|
-
}
|
|
751
|
-
const elements = tuple.map((value) => {
|
|
752
|
-
flattenedParams.push(value);
|
|
753
|
-
return formatPlaceholder(placeholderFormat, placeholderNumber++);
|
|
754
|
-
}).join(fragment.itemSeparator);
|
|
755
|
-
return `${fragment.itemPrefix}${elements}${fragment.itemSuffix}`;
|
|
756
|
-
}).join(fragment.groupSeparator);
|
|
757
|
-
return tupleList;
|
|
758
|
-
}
|
|
759
|
-
default:
|
|
760
|
-
assertNever(fragmentType, "Invalid fragment type");
|
|
761
|
-
}
|
|
762
|
-
}).join("");
|
|
820
|
+
for (const fragment of pairFragmentsWithParams(fragments, params)) {
|
|
821
|
+
flattenedParams.push(...flattenedFragmentParams(fragment));
|
|
822
|
+
sql += renderFragment(fragment, placeholderFormat, ctx);
|
|
823
|
+
}
|
|
763
824
|
return renderRawSql(sql, flattenedParams);
|
|
764
825
|
}
|
|
826
|
+
function renderFragment(fragment, placeholderFormat, ctx) {
|
|
827
|
+
const fragmentType = fragment.type;
|
|
828
|
+
switch (fragmentType) {
|
|
829
|
+
case "parameter":
|
|
830
|
+
return formatPlaceholder(placeholderFormat, ctx.placeholderNumber++);
|
|
831
|
+
case "stringChunk":
|
|
832
|
+
return fragment.chunk;
|
|
833
|
+
case "parameterTuple": {
|
|
834
|
+
const placeholders = fragment.value.length == 0 ? "NULL" : fragment.value.map(() => formatPlaceholder(placeholderFormat, ctx.placeholderNumber++)).join(",");
|
|
835
|
+
return `(${placeholders})`;
|
|
836
|
+
}
|
|
837
|
+
case "parameterTupleList": {
|
|
838
|
+
return fragment.value.map((tuple) => {
|
|
839
|
+
const elements = tuple.map(() => formatPlaceholder(placeholderFormat, ctx.placeholderNumber++)).join(fragment.itemSeparator);
|
|
840
|
+
return `${fragment.itemPrefix}${elements}${fragment.itemSuffix}`;
|
|
841
|
+
}).join(fragment.groupSeparator);
|
|
842
|
+
}
|
|
843
|
+
default:
|
|
844
|
+
assertNever(fragmentType, "Invalid fragment type");
|
|
845
|
+
}
|
|
846
|
+
}
|
|
765
847
|
function formatPlaceholder(placeholderFormat, placeholderNumber) {
|
|
766
848
|
return placeholderFormat.hasNumbering ? `${placeholderFormat.prefix}${placeholderNumber}` : placeholderFormat.prefix;
|
|
767
849
|
}
|
|
@@ -794,6 +876,143 @@ function toArgType(value) {
|
|
|
794
876
|
function doesRequireEvaluation(param) {
|
|
795
877
|
return isPrismaValuePlaceholder(param) || isPrismaValueGenerator(param);
|
|
796
878
|
}
|
|
879
|
+
function* pairFragmentsWithParams(fragments, params) {
|
|
880
|
+
let index = 0;
|
|
881
|
+
for (const fragment of fragments) {
|
|
882
|
+
switch (fragment.type) {
|
|
883
|
+
case "parameter": {
|
|
884
|
+
if (index >= params.length) {
|
|
885
|
+
throw new Error(`Malformed query template. Fragments attempt to read over ${params.length} parameters.`);
|
|
886
|
+
}
|
|
887
|
+
yield { ...fragment, value: params[index++] };
|
|
888
|
+
break;
|
|
889
|
+
}
|
|
890
|
+
case "stringChunk": {
|
|
891
|
+
yield fragment;
|
|
892
|
+
break;
|
|
893
|
+
}
|
|
894
|
+
case "parameterTuple": {
|
|
895
|
+
if (index >= params.length) {
|
|
896
|
+
throw new Error(`Malformed query template. Fragments attempt to read over ${params.length} parameters.`);
|
|
897
|
+
}
|
|
898
|
+
const value = params[index++];
|
|
899
|
+
yield { ...fragment, value: Array.isArray(value) ? value : [value] };
|
|
900
|
+
break;
|
|
901
|
+
}
|
|
902
|
+
case "parameterTupleList": {
|
|
903
|
+
if (index >= params.length) {
|
|
904
|
+
throw new Error(`Malformed query template. Fragments attempt to read over ${params.length} parameters.`);
|
|
905
|
+
}
|
|
906
|
+
const value = params[index++];
|
|
907
|
+
if (!Array.isArray(value)) {
|
|
908
|
+
throw new Error(`Malformed query template. Tuple list expected.`);
|
|
909
|
+
}
|
|
910
|
+
if (value.length === 0) {
|
|
911
|
+
throw new Error(`Malformed query template. Tuple list cannot be empty.`);
|
|
912
|
+
}
|
|
913
|
+
for (const tuple of value) {
|
|
914
|
+
if (!Array.isArray(tuple)) {
|
|
915
|
+
throw new Error(`Malformed query template. Tuple expected.`);
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
yield { ...fragment, value };
|
|
919
|
+
break;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
function* flattenedFragmentParams(fragment) {
|
|
925
|
+
switch (fragment.type) {
|
|
926
|
+
case "parameter":
|
|
927
|
+
yield fragment.value;
|
|
928
|
+
break;
|
|
929
|
+
case "stringChunk":
|
|
930
|
+
break;
|
|
931
|
+
case "parameterTuple":
|
|
932
|
+
yield* fragment.value;
|
|
933
|
+
break;
|
|
934
|
+
case "parameterTupleList":
|
|
935
|
+
for (const tuple of fragment.value) {
|
|
936
|
+
yield* tuple;
|
|
937
|
+
}
|
|
938
|
+
break;
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
function chunkParams(fragments, params, maxChunkSize) {
|
|
942
|
+
let totalParamCount = 0;
|
|
943
|
+
let maxParamsPerFragment = 0;
|
|
944
|
+
for (const fragment of pairFragmentsWithParams(fragments, params)) {
|
|
945
|
+
let paramSize = 0;
|
|
946
|
+
for (const _ of flattenedFragmentParams(fragment)) {
|
|
947
|
+
void _;
|
|
948
|
+
paramSize++;
|
|
949
|
+
}
|
|
950
|
+
maxParamsPerFragment = Math.max(maxParamsPerFragment, paramSize);
|
|
951
|
+
totalParamCount += paramSize;
|
|
952
|
+
}
|
|
953
|
+
let chunkedParams = [[]];
|
|
954
|
+
for (const fragment of pairFragmentsWithParams(fragments, params)) {
|
|
955
|
+
switch (fragment.type) {
|
|
956
|
+
case "parameter": {
|
|
957
|
+
for (const params2 of chunkedParams) {
|
|
958
|
+
params2.push(fragment.value);
|
|
959
|
+
}
|
|
960
|
+
break;
|
|
961
|
+
}
|
|
962
|
+
case "stringChunk": {
|
|
963
|
+
break;
|
|
964
|
+
}
|
|
965
|
+
case "parameterTuple": {
|
|
966
|
+
const thisParamCount = fragment.value.length;
|
|
967
|
+
let chunks = [];
|
|
968
|
+
if (maxChunkSize && // Have we split the parameters into chunks already?
|
|
969
|
+
chunkedParams.length === 1 && // Is this the fragment that has the most parameters?
|
|
970
|
+
thisParamCount === maxParamsPerFragment && // Do we need chunking to fit the parameters?
|
|
971
|
+
totalParamCount > maxChunkSize && // Would chunking enable us to fit the parameters?
|
|
972
|
+
totalParamCount - thisParamCount < maxChunkSize) {
|
|
973
|
+
const availableSize = maxChunkSize - (totalParamCount - thisParamCount);
|
|
974
|
+
chunks = chunkArray(fragment.value, availableSize);
|
|
975
|
+
} else {
|
|
976
|
+
chunks = [fragment.value];
|
|
977
|
+
}
|
|
978
|
+
chunkedParams = chunkedParams.flatMap((params2) => chunks.map((chunk) => [...params2, chunk]));
|
|
979
|
+
break;
|
|
980
|
+
}
|
|
981
|
+
case "parameterTupleList": {
|
|
982
|
+
const thisParamCount = fragment.value.reduce((acc, tuple) => acc + tuple.length, 0);
|
|
983
|
+
const completeChunks = [];
|
|
984
|
+
let currentChunk = [];
|
|
985
|
+
let currentChunkParamCount = 0;
|
|
986
|
+
for (const tuple of fragment.value) {
|
|
987
|
+
if (maxChunkSize && // Have we split the parameters into chunks already?
|
|
988
|
+
chunkedParams.length === 1 && // Is this the fragment that has the most parameters?
|
|
989
|
+
thisParamCount === maxParamsPerFragment && // Is there anything in the current chunk?
|
|
990
|
+
currentChunk.length > 0 && // Will adding this tuple exceed the max chunk size?
|
|
991
|
+
totalParamCount - thisParamCount + currentChunkParamCount + tuple.length > maxChunkSize) {
|
|
992
|
+
completeChunks.push(currentChunk);
|
|
993
|
+
currentChunk = [];
|
|
994
|
+
currentChunkParamCount = 0;
|
|
995
|
+
}
|
|
996
|
+
currentChunk.push(tuple);
|
|
997
|
+
currentChunkParamCount += tuple.length;
|
|
998
|
+
}
|
|
999
|
+
if (currentChunk.length > 0) {
|
|
1000
|
+
completeChunks.push(currentChunk);
|
|
1001
|
+
}
|
|
1002
|
+
chunkedParams = chunkedParams.flatMap((params2) => completeChunks.map((chunk) => [...params2, chunk]));
|
|
1003
|
+
break;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
return chunkedParams;
|
|
1008
|
+
}
|
|
1009
|
+
function chunkArray(array, chunkSize) {
|
|
1010
|
+
const result = [];
|
|
1011
|
+
for (let i = 0; i < array.length; i += chunkSize) {
|
|
1012
|
+
result.push(array.slice(i, i + chunkSize));
|
|
1013
|
+
}
|
|
1014
|
+
return result;
|
|
1015
|
+
}
|
|
797
1016
|
|
|
798
1017
|
// src/interpreter/serializeSql.ts
|
|
799
1018
|
import { ColumnTypeEnum } from "@prisma/driver-adapter-utils";
|
|
@@ -826,29 +1045,90 @@ function serializeSql(resultSet) {
|
|
|
826
1045
|
);
|
|
827
1046
|
}
|
|
828
1047
|
function serializeRawSql(resultSet) {
|
|
829
|
-
const types = resultSet.columnTypes.map((type) => serializeColumnType(type));
|
|
830
|
-
const mappers = types.map((type) => {
|
|
831
|
-
switch (type) {
|
|
832
|
-
case "bytes":
|
|
833
|
-
return (value) => Array.isArray(value) ? new Uint8Array(value) : value;
|
|
834
|
-
case "int":
|
|
835
|
-
return (value) => value === null ? null : typeof value === "number" ? value : parseInt(`${value}`, 10);
|
|
836
|
-
case "bigint":
|
|
837
|
-
return (value) => value === null ? null : typeof value === "bigint" ? value : BigInt(`${value}`);
|
|
838
|
-
case "json":
|
|
839
|
-
return (value) => typeof value === "string" ? JSON.parse(value) : value;
|
|
840
|
-
case "bool":
|
|
841
|
-
return (value) => typeof value === "string" ? value === "true" || value === "1" : typeof value === "number" ? value === 1 : value;
|
|
842
|
-
default:
|
|
843
|
-
return (value) => value;
|
|
844
|
-
}
|
|
845
|
-
});
|
|
846
1048
|
return {
|
|
847
1049
|
columns: resultSet.columnNames,
|
|
848
1050
|
types: resultSet.columnTypes.map((type) => serializeColumnType(type)),
|
|
849
|
-
rows: resultSet.rows.map(
|
|
1051
|
+
rows: resultSet.rows.map(
|
|
1052
|
+
(row) => row.map((value, index) => serializeRawValue(value, resultSet.columnTypes[index]))
|
|
1053
|
+
)
|
|
850
1054
|
};
|
|
851
1055
|
}
|
|
1056
|
+
function serializeRawValue(value, type) {
|
|
1057
|
+
if (value === null) {
|
|
1058
|
+
return null;
|
|
1059
|
+
}
|
|
1060
|
+
switch (type) {
|
|
1061
|
+
case ColumnTypeEnum.Int32:
|
|
1062
|
+
switch (typeof value) {
|
|
1063
|
+
case "number":
|
|
1064
|
+
return Math.trunc(value);
|
|
1065
|
+
case "string":
|
|
1066
|
+
return Math.trunc(Number(value));
|
|
1067
|
+
default:
|
|
1068
|
+
throw new Error(`Cannot serialize value of type ${typeof value} as Int32`);
|
|
1069
|
+
}
|
|
1070
|
+
case ColumnTypeEnum.Int32Array:
|
|
1071
|
+
if (!Array.isArray(value)) {
|
|
1072
|
+
throw new Error(`Cannot serialize value of type ${typeof value} as Int32Array`);
|
|
1073
|
+
}
|
|
1074
|
+
return value.map((v) => serializeRawValue(v, ColumnTypeEnum.Int32));
|
|
1075
|
+
case ColumnTypeEnum.Int64:
|
|
1076
|
+
switch (typeof value) {
|
|
1077
|
+
case "number":
|
|
1078
|
+
return BigInt(Math.trunc(value));
|
|
1079
|
+
case "string":
|
|
1080
|
+
return value;
|
|
1081
|
+
default:
|
|
1082
|
+
throw new Error(`Cannot serialize value of type ${typeof value} as Int64`);
|
|
1083
|
+
}
|
|
1084
|
+
case ColumnTypeEnum.Int64Array:
|
|
1085
|
+
if (!Array.isArray(value)) {
|
|
1086
|
+
throw new Error(`Cannot serialize value of type ${typeof value} as Int64Array`);
|
|
1087
|
+
}
|
|
1088
|
+
return value.map((v) => serializeRawValue(v, ColumnTypeEnum.Int64));
|
|
1089
|
+
case ColumnTypeEnum.Json:
|
|
1090
|
+
switch (typeof value) {
|
|
1091
|
+
case "string":
|
|
1092
|
+
return JSON.parse(value);
|
|
1093
|
+
default:
|
|
1094
|
+
throw new Error(`Cannot serialize value of type ${typeof value} as Json`);
|
|
1095
|
+
}
|
|
1096
|
+
case ColumnTypeEnum.JsonArray:
|
|
1097
|
+
if (!Array.isArray(value)) {
|
|
1098
|
+
throw new Error(`Cannot serialize value of type ${typeof value} as JsonArray`);
|
|
1099
|
+
}
|
|
1100
|
+
return value.map((v) => serializeRawValue(v, ColumnTypeEnum.Json));
|
|
1101
|
+
case ColumnTypeEnum.Bytes:
|
|
1102
|
+
if (Array.isArray(value)) {
|
|
1103
|
+
return new Uint8Array(value);
|
|
1104
|
+
} else {
|
|
1105
|
+
throw new Error(`Cannot serialize value of type ${typeof value} as Bytes`);
|
|
1106
|
+
}
|
|
1107
|
+
case ColumnTypeEnum.BytesArray:
|
|
1108
|
+
if (!Array.isArray(value)) {
|
|
1109
|
+
throw new Error(`Cannot serialize value of type ${typeof value} as BytesArray`);
|
|
1110
|
+
}
|
|
1111
|
+
return value.map((v) => serializeRawValue(v, ColumnTypeEnum.Bytes));
|
|
1112
|
+
case ColumnTypeEnum.Boolean:
|
|
1113
|
+
switch (typeof value) {
|
|
1114
|
+
case "boolean":
|
|
1115
|
+
return value;
|
|
1116
|
+
case "string":
|
|
1117
|
+
return value === "true" || value === "1";
|
|
1118
|
+
case "number":
|
|
1119
|
+
return value === 1;
|
|
1120
|
+
default:
|
|
1121
|
+
throw new Error(`Cannot serialize value of type ${typeof value} as Boolean`);
|
|
1122
|
+
}
|
|
1123
|
+
case ColumnTypeEnum.BooleanArray:
|
|
1124
|
+
if (!Array.isArray(value)) {
|
|
1125
|
+
throw new Error(`Cannot serialize value of type ${typeof value} as BooleanArray`);
|
|
1126
|
+
}
|
|
1127
|
+
return value.map((v) => serializeRawValue(v, ColumnTypeEnum.Boolean));
|
|
1128
|
+
default:
|
|
1129
|
+
return value;
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
852
1132
|
function serializeColumnType(columnType) {
|
|
853
1133
|
switch (columnType) {
|
|
854
1134
|
case ColumnTypeEnum.Int32:
|
|
@@ -1003,6 +1283,7 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1003
1283
|
#serializer;
|
|
1004
1284
|
#rawSerializer;
|
|
1005
1285
|
#provider;
|
|
1286
|
+
#connectioInfo;
|
|
1006
1287
|
constructor({
|
|
1007
1288
|
transactionManager,
|
|
1008
1289
|
placeholderValues,
|
|
@@ -1010,7 +1291,8 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1010
1291
|
tracingHelper,
|
|
1011
1292
|
serializer,
|
|
1012
1293
|
rawSerializer,
|
|
1013
|
-
provider
|
|
1294
|
+
provider,
|
|
1295
|
+
connectionInfo
|
|
1014
1296
|
}) {
|
|
1015
1297
|
this.#transactionManager = transactionManager;
|
|
1016
1298
|
this.#placeholderValues = placeholderValues;
|
|
@@ -1019,6 +1301,7 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1019
1301
|
this.#serializer = serializer;
|
|
1020
1302
|
this.#rawSerializer = rawSerializer ?? serializer;
|
|
1021
1303
|
this.#provider = provider;
|
|
1304
|
+
this.#connectioInfo = connectionInfo;
|
|
1022
1305
|
}
|
|
1023
1306
|
static forSql(options) {
|
|
1024
1307
|
return new _QueryInterpreter({
|
|
@@ -1028,7 +1311,8 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1028
1311
|
tracingHelper: options.tracingHelper,
|
|
1029
1312
|
serializer: serializeSql,
|
|
1030
1313
|
rawSerializer: serializeRawSql,
|
|
1031
|
-
provider: options.provider
|
|
1314
|
+
provider: options.provider,
|
|
1315
|
+
connectionInfo: options.connectionInfo
|
|
1032
1316
|
});
|
|
1033
1317
|
}
|
|
1034
1318
|
async run(queryPlan, queryable) {
|
|
@@ -1089,21 +1373,41 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1089
1373
|
};
|
|
1090
1374
|
}
|
|
1091
1375
|
case "execute": {
|
|
1092
|
-
const
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1376
|
+
const queries = renderQuery(node.args, scope, generators, this.#maxChunkSize());
|
|
1377
|
+
let sum = 0;
|
|
1378
|
+
for (const query of queries) {
|
|
1379
|
+
sum += await this.#withQuerySpanAndEvent(
|
|
1380
|
+
query,
|
|
1381
|
+
queryable,
|
|
1382
|
+
() => queryable.executeRaw(query).catch(
|
|
1383
|
+
(err) => node.args.type === "rawSql" ? rethrowAsUserFacingRawError(err) : rethrowAsUserFacing(err)
|
|
1384
|
+
)
|
|
1385
|
+
);
|
|
1386
|
+
}
|
|
1387
|
+
return { value: sum };
|
|
1096
1388
|
}
|
|
1097
1389
|
case "query": {
|
|
1098
|
-
const
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1390
|
+
const queries = renderQuery(node.args, scope, generators, this.#maxChunkSize());
|
|
1391
|
+
let results;
|
|
1392
|
+
for (const query of queries) {
|
|
1393
|
+
const result = await this.#withQuerySpanAndEvent(
|
|
1394
|
+
query,
|
|
1395
|
+
queryable,
|
|
1396
|
+
() => queryable.queryRaw(query).catch(
|
|
1397
|
+
(err) => node.args.type === "rawSql" ? rethrowAsUserFacingRawError(err) : rethrowAsUserFacing(err)
|
|
1398
|
+
)
|
|
1399
|
+
);
|
|
1400
|
+
if (results === void 0) {
|
|
1401
|
+
results = result;
|
|
1103
1402
|
} else {
|
|
1104
|
-
|
|
1403
|
+
results.rows.push(...result.rows);
|
|
1404
|
+
results.lastInsertId = result.lastInsertId;
|
|
1105
1405
|
}
|
|
1106
|
-
}
|
|
1406
|
+
}
|
|
1407
|
+
return {
|
|
1408
|
+
value: node.args.type === "rawSql" ? this.#rawSerializer(results) : this.#serializer(results),
|
|
1409
|
+
lastInsertId: results?.lastInsertId
|
|
1410
|
+
};
|
|
1107
1411
|
}
|
|
1108
1412
|
case "reverse": {
|
|
1109
1413
|
const { value, lastInsertId } = await this.interpretNode(node.args, queryable, scope, generators);
|
|
@@ -1182,43 +1486,12 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1182
1486
|
case "diff": {
|
|
1183
1487
|
const { value: from } = await this.interpretNode(node.args.from, queryable, scope, generators);
|
|
1184
1488
|
const { value: to } = await this.interpretNode(node.args.to, queryable, scope, generators);
|
|
1185
|
-
const toSet = new Set(asList(to));
|
|
1186
|
-
return { value: asList(from).filter((item) => !toSet.has(item)) };
|
|
1489
|
+
const toSet = new Set(asList(to).map((item) => JSON.stringify(item)));
|
|
1490
|
+
return { value: asList(from).filter((item) => !toSet.has(JSON.stringify(item))) };
|
|
1187
1491
|
}
|
|
1188
|
-
case "
|
|
1492
|
+
case "process": {
|
|
1189
1493
|
const { value, lastInsertId } = await this.interpretNode(node.args.expr, queryable, scope, generators);
|
|
1190
|
-
|
|
1191
|
-
const result = [];
|
|
1192
|
-
for (const item of asList(value)) {
|
|
1193
|
-
const key = getRecordKey(item, node.args.fields);
|
|
1194
|
-
if (!seen.has(key)) {
|
|
1195
|
-
seen.add(key);
|
|
1196
|
-
result.push(item);
|
|
1197
|
-
}
|
|
1198
|
-
}
|
|
1199
|
-
return { value: result, lastInsertId };
|
|
1200
|
-
}
|
|
1201
|
-
case "paginate": {
|
|
1202
|
-
const { value, lastInsertId } = await this.interpretNode(node.args.expr, queryable, scope, generators);
|
|
1203
|
-
const list = asList(value);
|
|
1204
|
-
const linkingFields = node.args.pagination.linkingFields;
|
|
1205
|
-
if (linkingFields !== null) {
|
|
1206
|
-
const groupedByParent = /* @__PURE__ */ new Map();
|
|
1207
|
-
for (const item of list) {
|
|
1208
|
-
const parentKey = getRecordKey(item, linkingFields);
|
|
1209
|
-
if (!groupedByParent.has(parentKey)) {
|
|
1210
|
-
groupedByParent.set(parentKey, []);
|
|
1211
|
-
}
|
|
1212
|
-
groupedByParent.get(parentKey).push(item);
|
|
1213
|
-
}
|
|
1214
|
-
const groupList = Array.from(groupedByParent.entries());
|
|
1215
|
-
groupList.sort(([aId], [bId]) => aId < bId ? -1 : aId > bId ? 1 : 0);
|
|
1216
|
-
return {
|
|
1217
|
-
value: groupList.flatMap(([, elems]) => paginate(elems, node.args.pagination)),
|
|
1218
|
-
lastInsertId
|
|
1219
|
-
};
|
|
1220
|
-
}
|
|
1221
|
-
return { value: paginate(list, node.args.pagination), lastInsertId };
|
|
1494
|
+
return { value: processRecords(value, node.args.operations), lastInsertId };
|
|
1222
1495
|
}
|
|
1223
1496
|
case "initializeRecord": {
|
|
1224
1497
|
const { lastInsertId } = await this.interpretNode(node.args.expr, queryable, scope, generators);
|
|
@@ -1240,6 +1513,34 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1240
1513
|
assertNever(node, `Unexpected node type: ${node.type}`);
|
|
1241
1514
|
}
|
|
1242
1515
|
}
|
|
1516
|
+
#maxChunkSize() {
|
|
1517
|
+
if (this.#connectioInfo?.maxBindValues !== void 0) {
|
|
1518
|
+
return this.#connectioInfo.maxBindValues;
|
|
1519
|
+
}
|
|
1520
|
+
return this.#providerMaxChunkSize();
|
|
1521
|
+
}
|
|
1522
|
+
#providerMaxChunkSize() {
|
|
1523
|
+
if (this.#provider === void 0) {
|
|
1524
|
+
return void 0;
|
|
1525
|
+
}
|
|
1526
|
+
switch (this.#provider) {
|
|
1527
|
+
case "cockroachdb":
|
|
1528
|
+
case "postgres":
|
|
1529
|
+
case "postgresql":
|
|
1530
|
+
case "prisma+postgres":
|
|
1531
|
+
return 32766;
|
|
1532
|
+
case "mysql":
|
|
1533
|
+
return 65535;
|
|
1534
|
+
case "sqlite":
|
|
1535
|
+
return 999;
|
|
1536
|
+
case "sqlserver":
|
|
1537
|
+
return 2098;
|
|
1538
|
+
case "mongodb":
|
|
1539
|
+
return void 0;
|
|
1540
|
+
default:
|
|
1541
|
+
assertNever(this.#provider, `Unexpected provider: ${this.#provider}`);
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1243
1544
|
#withQuerySpanAndEvent(query, queryable, execute) {
|
|
1244
1545
|
return withQuerySpanAndEvent({
|
|
1245
1546
|
query,
|
|
@@ -1317,18 +1618,6 @@ function attachChildrenToParents(parentRecords, children) {
|
|
|
1317
1618
|
}
|
|
1318
1619
|
return parentRecords;
|
|
1319
1620
|
}
|
|
1320
|
-
function paginate(list, { cursor, skip, take }) {
|
|
1321
|
-
const cursorIndex = cursor !== null ? list.findIndex((item) => doKeysMatch(item, cursor)) : 0;
|
|
1322
|
-
if (cursorIndex === -1) {
|
|
1323
|
-
return [];
|
|
1324
|
-
}
|
|
1325
|
-
const start = cursorIndex + (skip ?? 0);
|
|
1326
|
-
const end = take !== null ? start + take : list.length;
|
|
1327
|
-
return list.slice(start, end);
|
|
1328
|
-
}
|
|
1329
|
-
function getRecordKey(record, fields) {
|
|
1330
|
-
return JSON.stringify(fields.map((field) => record[field]));
|
|
1331
|
-
}
|
|
1332
1621
|
function evalFieldInitializer(initializer, lastInsertId, scope, generators) {
|
|
1333
1622
|
switch (initializer.type) {
|
|
1334
1623
|
case "value":
|
|
@@ -1409,6 +1698,35 @@ function mapObjectValues(object, mapper) {
|
|
|
1409
1698
|
return result;
|
|
1410
1699
|
}
|
|
1411
1700
|
|
|
1701
|
+
// src/raw-json-protocol.ts
|
|
1702
|
+
import Decimal4 from "decimal.js";
|
|
1703
|
+
function normalizeRawJsonProtocolResponse(response) {
|
|
1704
|
+
for (let i = 0; i < response.rows.length; i++) {
|
|
1705
|
+
const row = response.rows[i];
|
|
1706
|
+
for (let j = 0; j < row.length; j++) {
|
|
1707
|
+
row[j] = normalizeValue(response.types[j], row[j]);
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
return response;
|
|
1711
|
+
}
|
|
1712
|
+
function normalizeValue(type, value) {
|
|
1713
|
+
if (value === null) {
|
|
1714
|
+
return value;
|
|
1715
|
+
}
|
|
1716
|
+
switch (type) {
|
|
1717
|
+
case "bigint":
|
|
1718
|
+
return String(BigInt(value));
|
|
1719
|
+
case "decimal":
|
|
1720
|
+
return String(new Decimal4(value));
|
|
1721
|
+
case "bigint-array":
|
|
1722
|
+
return value.map((v) => normalizeValue("bigint", v));
|
|
1723
|
+
case "decimal-array":
|
|
1724
|
+
return value.map((v) => normalizeValue("decimal", v));
|
|
1725
|
+
default:
|
|
1726
|
+
return value;
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1412
1730
|
// src/transactionManager/TransactionManager.ts
|
|
1413
1731
|
import { Debug } from "@prisma/debug";
|
|
1414
1732
|
|
|
@@ -1684,5 +2002,6 @@ export {
|
|
|
1684
2002
|
isPrismaValuePlaceholder,
|
|
1685
2003
|
noopTracingHelper,
|
|
1686
2004
|
normalizeJsonProtocolValues,
|
|
2005
|
+
normalizeRawJsonProtocolResponse,
|
|
1687
2006
|
safeJsonStringify
|
|
1688
2007
|
};
|