From 48fa205288558142941fea58dfb6ae7ad78d7716 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 4 Dec 2020 19:07:28 +0000 Subject: [PATCH] Error if the number of parameters changes --- packages/react-pg/src/ReactPostgres.js | 21 +++++++++++++++++++-- scripts/error-codes/codes.json | 4 +++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/packages/react-pg/src/ReactPostgres.js b/packages/react-pg/src/ReactPostgres.js index fc4eae302a320..b15cb80fda972 100644 --- a/packages/react-pg/src/ReactPostgres.js +++ b/packages/react-pg/src/ReactPostgres.js @@ -12,6 +12,7 @@ import type {Wakeable} from 'shared/ReactTypes'; import {unstable_getCacheForType} from 'react'; import {Pool as PostgresPool} from 'pg'; import {prepareValue} from 'pg/lib/utils'; +import invariant from 'shared/invariant'; const Pending = 0; const Resolved = 1; @@ -74,11 +75,13 @@ export function Pool(options: mixed) { }; } +type NestedMap = Map; + Pool.prototype.query = function(query: string, values?: Array) { const pool = this.pool; const outerMap = unstable_getCacheForType(this.createResultMap); - let innerMap: Map = outerMap; + let innerMap: NestedMap = outerMap; let key = query; if (values != null) { // If we have parameters, each becomes as a nesting layer for Maps. @@ -88,6 +91,13 @@ Pool.prototype.query = function(query: string, values?: Array) { if (nextMap === undefined) { nextMap = new Map(); innerMap.set(key, nextMap); + } else if (!(nextMap instanceof Map)) { + invariant( + false, + 'This query has received more parameters compared to ' + + 'the last time the same query was used. Always pass the exact number of ' + + 'parameters that the query needs, every time you use it.', + ); } innerMap = nextMap; // Postgres bindings convert everything to strings: @@ -97,11 +107,18 @@ Pool.prototype.query = function(query: string, values?: Array) { } } - let entry: Result | void = innerMap.get(key); + let entry = innerMap.get(key); if (!entry) { const thenable = pool.query(query, values); entry = toResult(thenable); innerMap.set(key, entry); + } else if (entry instanceof Map) { + invariant( + false, + 'This query has received fewer parameters compared to ' + + 'the last time the same query was used. Always pass the exact number of ' + + 'parameters that the query needs, every time you use it.', + ); } return readResult(entry); }; diff --git a/scripts/error-codes/codes.json b/scripts/error-codes/codes.json index 444e3ff809229..d3104201c97c2 100644 --- a/scripts/error-codes/codes.json +++ b/scripts/error-codes/codes.json @@ -369,5 +369,7 @@ "378": "Type %s is not supported in client component props. Remove %s from this object, or avoid the entire object: %s", "379": "Refs cannot be used in server components, nor passed to client components.", "380": "Reading the cache is only supported while rendering.", - "381": "This feature is not supported by ReactSuspenseTestUtils." + "381": "This feature is not supported by ReactSuspenseTestUtils.", + "382": "This query has received more parameters compared to the last time the same query was used. Always pass the exact number of parameters that the query needs, every time you use it.", + "383": "This query has received fewer parameters compared to the last time the same query was used. Always pass the exact number of parameters that the query needs, every time you use it." }