Repository: brianc/node-postgres (JavaScript)

Issue:
Custom type parsers do not run for multi-line statements
## Minimal reproducible example

See https://github.com/mantariksh/pg-bug-repro/blob/main/pg.mjs, the instructions are in the README.

## Behaviour observed

When I pass a custom type parser via the `types.getTypeParser` function passed to the `Client` constructor, the type parser runs correctly for single-line statements but not for multi-line statements.

For instance, consider the following table (where `enum_Users_roles` has two possible values, `Admin` and `View`)
```
CREATE TABLE IF NOT EXISTS "Users" ("id"   SERIAL , "name" VARCHAR(255), "roles" "public"."enum_Users_roles"[], PRIMARY KEY ("id"));
```

I want `Client` to check for any values wrapped in braces (`{}`) and parse them as an array, as follows:
```javascript
const getTypeParser = () => {
  return (value) => {
    if (
      typeof value === "string" &&
      value.startsWith("{") &&
      value.endsWith("}")
    ) {
      return value.slice(1, -1).split(",");
    }
    return value;
  };
};

const client = new Client({
  connectionString: CONNECTION_STRING,
  types: {
    getTypeParser,
  },
});
```

When I run a single-line statement, I get the correct result:
```JavaScript
const singleStatementResult = await client.query(
  'INSERT INTO "Users" ("id","name","roles") VALUES (DEFAULT,$1,$2) RETURNING "id","name","roles";',
  ["Name", ["Admin", "View"]]
);
console.log(singleStatementResult.rows);
// Console output with array correctly parsed
// [ { id: '1', name: 'Name', roles: [ 'Admin', 'View' ] } ]
```

However, when I run a multi-line statement, the array is no longer parsed (sorry that the SQL statement here is somewhat complex, I got it directly from `sequelize`):
```JavaScript
const multiStatementResult = await client.query(
    `CREATE OR REPLACE FUNCTION pg_temp.testfunc(OUT response "Users", OUT sequelize_caught_exception text) RETURNS RECORD AS $func_6020ceb2c2d3491c8a77fe107dbabe02$ BEGIN INSERT INTO "Users" ("id","name","roles") VALUES (DEFAULT,'Name',ARRAY['Admin','View']::"enum_Users_roles"[]) RETURNING * INTO response; EXCEPTION WHEN unique_violation THEN GET STACKED DIAGNOSTICS sequelize_caught_exception = PG_EXCEPTION_DETAIL; END $func_6020ceb2c2d3491c8a77fe107dbabe02$ LANGUAGE plpgsql; SELECT (testfunc.response)."id", (testfunc.response)."name", (testfunc.response)."roles", testfunc.sequelize_caught_exception FROM pg_temp.testfunc(); DROP FUNCTION IF EXISTS pg_temp.testfunc();`
);
multiStatementResult.forEach((result) => {
  if (result.rows.length) {
    console.log(result.rows);
  }
});

// Console output, observe array is not parsed
// [
//   {
//     id: 2,
//     name: 'Name',
//     roles: '{Admin,View}',
//     sequelize_caught_exception: null
//   }
// ]
```


Discussion:
Although this could just be a simplified example, I might as well mention that detecting braces is a bad idea, especially globally in every value processed by a pg client. In real code, if you want to use pg’s `types` option for this, you should get the array OID for your enum and [set a parser specifically for it](https://github.com/brianc/node-pg-types/blob/1102a81a9ef96e763f1b530093a4603e334437b2/README.md) that *always* parses it as an array (with or without [postgres-array](https://www.npmjs.com/package/postgres-array)). But maybe you *don’t* want to use pg’s `types` option for this – it might be better handled at the SQL layer by casting the enum-typed array to `text[]`, or at a higher layer than pg that knows about the schema.
@charmander thanks for responding! This is just a simplified example for the sake of illustrating the bug. I actually encountered this bug as a user of `sequelize`, which does exactly what you said (get the array OID, set a specific parser), but I traced the bug to this library so thought I'd propose a fix here.

Relevant `sequelize` code here: https://github.com/sequelize/sequelize/blob/b9e71a7af57568dd85b8a2fdaac59b96ce0f0e95/src/dialects/postgres/connection-manager.js#L81



Patch:
diff --git a/packages/pg/lib/query.js b/packages/pg/lib/query.js
index 0925960e6..fbef341bf 100644
--- a/packages/pg/lib/query.js
+++ b/packages/pg/lib/query.js
@@ -65,7 +65,7 @@ class Query extends EventEmitter {
       if (!Array.isArray(this._results)) {
         this._results = [this._result]
       }
-      this._result = new Result(this._rowMode, this.types)
+      this._result = new Result(this._rowMode, this._result._types)
       this._results.push(this._result)
     }
   }


Test patch:
diff --git a/packages/pg/test/integration/client/custom-types-tests.js b/packages/pg/test/integration/client/custom-types-tests.js
index b3446cff0..eb5fa892c 100644
--- a/packages/pg/test/integration/client/custom-types-tests.js
+++ b/packages/pg/test/integration/client/custom-types-tests.js
@@ -22,6 +22,21 @@ suite.test('custom type parser in client config', (done) => {
   })
 })
 
+suite.test('custom type parser in client config with multiple results', (done) => {
+  const client = new Client({ types: customTypes })
+
+  client.connect().then(() => {
+    client.query(
+      `SELECT 'foo'::text as name; SELECT 'bar'::text as baz`,
+      assert.success(function (res) {
+        assert.equal(res[0].rows[0].name, 'okay!')
+        assert.equal(res[1].rows[0].baz, 'okay!')
+        client.end().then(done)
+      })
+    )
+  })
+})
+
 // Custom type-parsers per query are not supported in native
 if (!helper.args.native) {
   suite.test('custom type parser in query', (done) => {