salsita / node-pg-migrate

Node.js database migration management for PostgreSQL
https://salsita.github.io/node-pg-migrate
MIT License
1.26k stars 174 forks source link

Feature: Support plain json objects for jsonb defaults. #744

Open rijnhard opened 3 years ago

rijnhard commented 3 years ago

it should be possible to specify a jsonb fields default value as a plain js object.

Error

CREATE TABLE "my_table" (
  "id" serial PRIMARY KEY,
  "my_column" jsonb DEFAULT  NOT NULL
                             ^^^^
);

Migrations failed error: syntax error at or near "NOT"
    at Parser.parseErrorMessage (/Data/Projects/Infrastructure/azure-archiver/node_modules/pg-protocol/src/parser.ts:357:11)
    at Parser.handlePacket (/Data/Projects/Infrastructure/azure-archiver/node_modules/pg-protocol/src/parser.ts:186:21)
    at Parser.parse (/Data/Projects/Infrastructure/azure-archiver/node_modules/pg-protocol/src/parser.ts:101:30)
    at Socket.<anonymous> (/Data/Projects/Infrastructure/azure-archiver/node_modules/pg-protocol/src/index.ts:7:48)

Code

// this is ideal
pgm.addColumn('my_table', 'my_column', {
    type: 'jsonb',
    notNull: true,
    default: { attempts: 0, uploads: 0 }
});

// this is whats required:
pgm.addColumn('my_table', 'my_column', {
    type: 'jsonb',
    notNull: true,
    default: pgm.func(`'{ "attempts": 0, "uploads": 0 }'::jsonb`)
});

Suggestion

a naive psuedo-implementation

const JSON_FIELDS = ['json', 'jsonb];

if (column.notNull
    && column.default != null
    && JSON_FIELDS.includes(column.type)
) {
    if (!lodash.isplainobject(column.default)) {
        throw new Error(`${column.type} defaults can only be plain objects`);
    }

    const defaultStatement = `'${JSON.serialize(column.default)}'::${column.type}`
}
goce-cz commented 3 years ago

Hello Rijnhard,

Thank you for your suggestion. We will consider adding this feature to one of the next releases.

However please note that there is a quite comfortable workaround as you yourself wrote, so this feature will probably not be the top-priority.