From baa58b17a7fd57e838d7143dbe1de1ee2cd3e337 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 4 Dec 2020 19:11:53 +0000 Subject: [PATCH] Error when the number of parameters to a query 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 fc4eae302a32..b3eea21ff082 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 than the last time ' + + 'the same query was used. Always pass the exact number of ' + + 'parameters that the query needs.', + ); } 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 than the last time ' + + 'the same query was used. Always pass the exact number of ' + + 'parameters that the query needs.', + ); } return readResult(entry); }; diff --git a/scripts/error-codes/codes.json b/scripts/error-codes/codes.json index 444e3ff80922..641901fcaba0 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 than the last time the same query was used. Always pass the exact number of parameters that the query needs.", + "383": "This query has received fewer parameters than the last time the same query was used. Always pass the exact number of parameters that the query needs." }