David Emami
David Emami

Reputation: 229

Need working example of a custom Sequelize Postgres datatype

I have a custom type in Postgres that I want to use in Sequelize. I've written code based on the example in the Sequelize docs, except for call to a function ("inherits") which I can't find in Sequelize or elsewhere. However, using sequelize.define to create a model with an attribute of this custom type throws an exception inside Sequelize. Is there an error in my code that stands out? Or is there another good example or tutorial for implementing a custom datatype? Also, what's up with the "inherits" function shown in the doc example -- are the docs leaving out an import/requires, or is that call erroneous?

Docs I'm following are here: http://docs.sequelizejs.com/manual/data-types.html#extending-datatypes

The type as defined in Postgres:

CREATE TYPE public.measurement AS
(
    unit text,
    value double precision
);

My test code in NodeJS:

const Sequelize = require('sequelize');

let dataTypes = Sequelize.DataTypes;

// Create class for custom datatype
class MEASUREMENT extends dataTypes.ABSTRACT {
    toSql() {
        console.log('MEASUREMENT toSql');
        return 'MEASUREMENT';
    }
    static parse(value) {
        console.log('MEASUREMENT parse value=', value);
        return value;
    }
};

// Set key
MEASUREMENT.prototype.key = 'MEASUREMENT';
MEASUREMENT.key = MEASUREMENT.prototype.key;

// Add to DataTypes
dataTypes.MEASUREMENT = MEASUREMENT;

// Add to Sequelize
Sequelize.MEASUREMENT = Sequelize.Utils.classToInvokable(MEASUREMENT);

let pgTypes = dataTypes.postgres;

// Map dialects
dataTypes.MEASUREMENT.types.postgres = ['MEASUREMENT']

pgTypes.MEASUREMENT = function MEASUREMENT() {
    if (!(this instanceof pgTypes.MEASUREMENT)) return new pgTypes.MEASUREMENT();
    DataTypes.MEASUREMENT.apply(this, arguments);
}

// inherits(pgTypes.MEASUREMENT, dataTypes.MEASUREMENT);
// Node throws a parse error. This is in the example in the Sequelize docs, however.

pgTypes.MEASUREMENT.parse = dataTypes.MEASUREMENT.parse;


// ------------------------------

const sequelize = new Sequelize('test', 'test', 'test', {
    host: 'localhost',
    dialect: 'postgres'
});

const Thing = sequelize.define('thing', {
    name: Sequelize.STRING,
    weight: Sequelize.MEASUREMENT
});

Call stack when run:

C:\Workspaces\nebula\server\node_modules\sequelize\lib\dialects\abstract\connection-manager.js:48
        if (dataType.types[this.dialectName]) {                                                                         
                          ^                                                                                             

TypeError: Cannot read property 'postgres' of undefined                                                                 
    at _.each.dataType (C:\Workspaces\nebula\server\node_modules\sequelize\lib\dialects\abstract\connection-manager.js:48:27)                                                                                                                   
    at C:\Workspaces\nebula\server\node_modules\lodash\lodash.js:4911:15                                                
    at baseForOwn (C:\Workspaces\nebula\server\node_modules\lodash\lodash.js:2996:24)                                   
    at C:\Workspaces\nebula\server\node_modules\lodash\lodash.js:4880:18                                                
    at Function.forEach (C:\Workspaces\nebula\server\node_modules\lodash\lodash.js:9344:14)                             
    at ConnectionManager.refreshTypeParser (C:\Workspaces\nebula\server\node_modules\sequelize\lib\dialects\abstract\connection-manager.js:46:7)                                                                                                
    at new ConnectionManager (C:\Workspaces\nebula\server\node_modules\sequelize\lib\dialects\postgres\connection-manager.js:23:10)                                                                                                             
    at new PostgresDialect (C:\Workspaces\nebula\server\node_modules\sequelize\lib\dialects\postgres\index.js:14:30)    
    at new Sequelize (C:\Workspaces\nebula\server\node_modules\sequelize\lib\sequelize.js:320:20)                       
    at Object.<anonymous> (C:\Workspaces\nebula\server\testsequelizecustom.js:58:19)                                    
    at Module._compile (internal/modules/cjs/loader.js:689:30)                                                          
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)                                            
    at Module.load (internal/modules/cjs/loader.js:599:32)                                                              
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)                                                            
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)                                                     
    at Function.Module.runMain (internal/modules/cjs/loader.js:742:12)                                                  
    at startup (internal/bootstrap/node.js:279:19)                                                                      
    at bootstrapNodeJSCore (internal/bootstrap/node.js:752:3)                                                           

Upvotes: 8

Views: 1271

Answers (1)

David
David

Reputation: 1111

To fix the error, we need to cause the property postgres on the object dataType.types to be defined.

Just under the line you already have:

pgTypes.MEASUREMENT.parse = dataTypes.MEASUREMENT.parse;

Add the following line, and the error should go away:

pgTypes.MEASUREMENT.types = {postgres:[‘MEASUREMENT’]};

You'll probably also need to add this line, to handle a related error (see below).

dataTypes.postgres.MEASUREMENT.key = ‘MEASUREMENT’;

The related error:

[...]/node_modules/sequelize/lib/dialects/postgres/connection-manager.js:36
if (dataType.key.toLowerCase() === 'range') {
                         ^
    
TypeError: Cannot read property 'toLowerCase' of undefined

Upvotes: 5

Related Questions