Search code examples
postgresqlsequelize.jsfull-text-searchtsvector

How to create this tsvector generated always as column with sequelize?


I see that sequelize has DataTypes.TSVECTOR for postgres dialect. I have a column whose definition in raw SQL is as follows

tsvector GENERATED ALWAYS AS (((
setweight(to_tsvector('english'::regconfig, (COALESCE(title, ''::character varying))::text), 'A'::"char") || 
setweight(to_tsvector('english'::regconfig, COALESCE(summary, ''::text)), 'B'::"char")) || 
setweight(to_tsvector('english'::regconfig, (COALESCE(content, ''::character varying))::text), 'C'::"char"))) 
STORED

How can I define this in my sequelize model

  const FeedItem = sequelize.define(
    'FeedItem', {
        feedItemId: {
            type: DataTypes.UUID,
            primaryKey: true,
            allowNull: false,
            defaultValue: DataTypes.UUIDV4,
        },
        pubdate: {
            type: DataTypes.DATE,
            allowNull: false,
            defaultValue: sequelize.literal('CURRENT_TIMESTAMP'),
            validate: {
                isDate: true,
            },
        },
        link: {
            type: DataTypes.STRING,
            allowNull: false,
            validate: {
                len: [0, 2047],
            },
        },
        guid: {
            type: DataTypes.STRING,
            validate: {
                len: [0, 2047],
            },
        },
        title: {
            type: DataTypes.TEXT,
            allowNull: false,
            validate: {
                len: [0, 65535],
            },
        },
        summary: {
            type: DataTypes.TEXT,
            validate: {
                len: [0, 65535],
            },
        },
        content: {
            type: DataTypes.TEXT,
            validate: {
                len: [0, 1048575],
            },
        },
        author: {
            type: DataTypes.STRING,
            validate: {
                len: [0, 63],
            },
        },
        tags: {
            type: DataTypes.ARRAY(DataTypes.STRING),
            defaultValue: [],
        },
        // How to do that generated always part here???
        searchable: {
            type: DataTypes.TSVECTOR
        },
    }, {
        timestamps: false,
        underscored: true,
        indexes: [
            {
                name: 'idx_feed_items_searchable',
                fields: ['searchable'],
                using: 'gin',
            },
        ],
    }
  );

Solution

  • The model needs to be modified as follows to get this working

      const FeedItem = sequelize.define(
        'FeedItem',
        {
          feedItemId: {
            type: DataTypes.UUID,
            primaryKey: true,
            allowNull: false,
            defaultValue: DataTypes.UUIDV4,
          },
          pubdate: {
            type: DataTypes.DATE,
            allowNull: false,
            defaultValue: sequelize.literal('CURRENT_TIMESTAMP'),
            validate: {
              isDate: true,
            },
          },
          link: {
            type: DataTypes.STRING,
            allowNull: false,
            validate: {
              len: [0, 2047],
            },
          },
          guid: {
            type: DataTypes.STRING,
            validate: {
              len: [0, 2047],
            },
          },
          title: {
            type: DataTypes.TEXT,
            allowNull: false,
            validate: {
              len: [0, 65535],
            },
          },
          summary: {
            type: DataTypes.TEXT,
            validate: {
              len: [0, 65535],
            },
          },
          content: {
            type: DataTypes.TEXT,
            validate: {
              len: [0, 1048575],
            },
          },
          author: {
            type: DataTypes.STRING,
            validate: {
              len: [0, 63],
            },
          },
          tags: {
            type: DataTypes.ARRAY(DataTypes.STRING),
            defaultValue: [],
          },
          // https://stackoverflow.com/questions/67051281/use-postgres-generated-columns-in-sequelize-model
          searchable: {
            type: `tsvector GENERATED ALWAYS AS (((setweight(to_tsvector('english'::regconfig, (COALESCE(title, ''::character varying))::text), 'A'::"char") || setweight(to_tsvector('english'::regconfig, COALESCE(summary, ''::text)), 'B'::"char")) || setweight(to_tsvector('english'::regconfig, (COALESCE(content, ''::character varying))::text), 'C'::"char"))) STORED`,
            set() {
              throw new Error('generatedValue is read-only');
            },
          },
        },
        {
          timestamps: false,
          underscored: true,
          indexes: [
            {
              name: 'idx_feed_items_pubdate_feed_item_id_desc',
              fields: [
                { attribute: 'pubdate', order: 'DESC' },
                { attribute: 'feed_item_id', order: 'DESC' },
              ],
            },
            {
              name: 'idx_feed_items_tags',
              fields: ['tags'],
              using: 'gin',
            },
            {
              name: 'idx_feed_items_searchable',
              fields: ['searchable'],
              using: 'gin',
            },
          ],
        }
      );
    

    Does not work with sequelize.sync({alter: true}) you have to force:true or sequelize migrations