sequelize: Can't change default parser for Postgresql using setTypeParser after version 4.32.3
What are you doing?
I’m trying to change the default parser for decimal type (numeric in postgresql) from string to float using the following code:
var pg = require('pg');
pg.types.setTypeParser(1700, 'text', parseFloat);
This was working until version 4.32.4
What do you expect to happen?
The same behavior prior to version 4.32.4
What is actually happening?
The parser doesn’t change.
Dialect: postgres Dialect version: 7.4.1 Database version: 9.6 Sequelize version: 4.33.4
Note : Your issue may be ignored OR closed by maintainers if it’s not tested against latest version OR does not follow issue template.
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 4
- Comments: 20 (5 by maintainers)
@EyePulp @psotres
I would like to start by thanking you, your help was invaluable.
Having a look it seems we can get the workaround to look a little cleaner by extending the class instead of trying to clone the entire object.
Defining our CustomDecimal as follows alllows us to override the parse function and keep all of the other information associated.
This enables us to make the hook itself a bit cleaner.
May be important to mention that I am using TypeScript. Hopefully this helps!
After digging through the code, I was able to get it to work with this
Wonder how long this hack will last…
Edit: The old
pg.types.setTypeParser
method still works for other DataTypes, like DATEONLY (1082). I’m a bit confused on what is going on in the code…@EyePulp - I’m happy to give it a go - but have no way to verify right now.
Removing Typescript related code gives the following:
Good luck!
@psotres This seemed to rear its head again under v5.x. The final call to
would fail – it seems like the duped type
{ ...this.Sequelize.DataTypes.postgres.DECIMAL }
wasn’t pulling all the properties –.DECIMAL
is a Function with additional properties hung on it, such askey
,types
,parse
etc…Also under v5 there doesn’t seem to be a
this.Sequelize
in scope whenafterConnect
runssetParsers()
– there is athis.sequelize
(note the lower case), but it doesn’t have the.DataTypes
property. I instead used theSequelize
from my upper scoped initial import of the library.I couldn’t seem to clone it in a one-liner and keep those properties, so I wrote a cloning function to grab some things both manually and via
Object.getOwnPropertyNames()
This is starting to feel pretty hacky, but tests are passing. 🤷♂
Happy to use a different approach if a better one exists!
For anyone facing the same problem as @k98kumar, refer to https://sequelize.org/master/manual/hooks.html. It seems like @EyePulp is referring to Permanent Hooks, they can be added this way for example:
Anyway, @EyePulp’s workaround works for me, thanks
I’ve also been digging though the code and problem seems to have been introduced with #9025 and #9026.
The way the parser is stored for future usage in the connectionManager (via a function that will call
dataType.parse
method when needed instead of storing its current reference) makes adding custom parser logic quite obscure if you don’t clone thedataType
object, as a subsequent modification ofSequelize.DataTypes.postgres.*.parse
value in another sequelize instance will impact all instances.My current workaround to solve the problem without having to use the hack provided by @kingjerod (which is a valid solution but it impacts all sequelize instances) is this:
Nevertheless, as a
getTypeParser(oid)
method is already there, I would say the more elegant way to provide the functionality is via a newsetTypeParser(oid, parser)
method.Edit: I ended up using an
afterConnect
hook to configure it because https://github.com/sequelize/sequelize/blob/ee9ec57d2d4f3b59515d9d4745caff447227b81a/lib/dialects/postgres/connection-manager.js#L181 overwrites the parsers a single time after the first connection is made:Note: it uses once to avoid a refresh every time db is reconnected, but it can be easily done without the dependency.
This workaround worked with version 6.33, thank you
I get the following error: “Base constructors must all have the same return type.”
Could you tell me how can I fix it?
@EyePulp I’m using v5.x, but when I use the hooks, I get:
Error: Unrecognized datatype for attribute "rating.hooks"
withInstead I used the addHook function:
Assuming I used the addHook function correctly, I still got DECIMAL numbers in string format. Am I forgetting to do something or did I not set addHook up correctly?
Also for the DECIMAL and other types in
dTypes
, shouldn’t it have to account for nulls? So should it be like:cloneType(DataTypes.DECIMAL, v => v && parseFloat(v)