pg-mem
pg-mem copied to clipboard
Default values are evaluated at column creation time rather than insert time
Describe the bug
The Postgres documentation specifically mentions that default values should be evaluated when a record is inserted, not when the table is created: https://www.postgresql.org/docs/current/ddl-default.html The current implementation seems to evaluate default values at table creation time, breaking many common default value use cases.
QueryError: insert into "devices" ("value") values ($1), ($2) - ERROR: insert into "devices" (value, id) values ($1, $2) returning "id" - duplicate key value violates unique constraint "devices_pkey"
DETAIL: Key (id)=(cfeea46a-be4d-45f4-ba47-21fe2316eeb9) already exists.
🐜 This seems to be an execution error, which means that your request syntax seems okay,
but the resulting statement cannot be executed → Probably not a pg-mem error.
*️⃣ Failed SQL statement: insert into "devices" ("value") values ('1'), ('2');
👉 You can file an issue at https://github.com/oguimbal/pg-mem along with a way to reproduce this error (if you can), and the stacktrace:
at BIndex.add (/node_modules/pg-mem/index.js:9506:19)
at MemoryTable.indexElt (/node_modules/pg-mem/index.js:8276:21)
at MemoryTable.doInsert (/node_modules/pg-mem/index.js:8155:14)
at Insert.performMutation (/node_modules/pg-mem/index.js:9239:33)
at Insert._doExecuteOnce (/node_modules/pg-mem/index.js:4335:29)
at Insert.enumerate (/node_modules/pg-mem/index.js:4343:31)
at enumerate.next (<anonymous>)
at SelectExec.execute (/node_modules/pg-mem/index.js:3451:75)
at /node_modules/pg-mem/index.js:5975:42
at pushExecutionCtx (/node_modules/pg-mem/index.js:588:16) {
data: {
error: 'insert into "devices" (value, id) values ($1, $2) returning "id" - duplicate key value violates unique constraint "devices_pkey"',
details: 'Key (id)=(cfeea46a-be4d-45f4-ba47-21fe2316eeb9) already exists.',
code: '23505'
},
code: '23505',
location: { start: 0, end: 0 },
[Symbol(errorDetailsIncluded)]: true
}
To Reproduce
package.json:
{
"type": "module",
"dependencies": {
"knex": "2.5.1",
"pg-mem": "2.6.13"
}
}
index.js:
import { newDb, DataType } from 'pg-mem';
import { randomUUID } from 'node:crypto';
const database = newDb();
const knex = database.adapters.createKnex();
database.public.registerFunction({
name: 'uuid',
args: [],
returns: DataType.uuid,
implementation: () => randomUUID(),
});
await knex.schema.createTable('devices', (table) => {
table.uuid('id').primary().notNullable().defaultsTo(knex.raw('UUID()'));
table.string('value');
});
await knex.table('devices').insert([{value: '1'}, {value: '2'}]);
knex.destroy();
pg-mem version
2.6.13
Same issue using :
- typeorm:
9.0.1
- pg-mem:
2.7.1
@oguimbal Any hints to where we can start if we want to fix this? I just started using pg-mem and am open to contributing to this issue.
Found a workaround. Since it's evaluating only once, a peek through the code suggested that it's simply checking for the type of function and evaluating in case it's a function. So, double wrapping the evaluator works. For the above example, this should work,
database.public.registerFunction({
name: 'uuid',
args: [],
returns: DataType.uuid,
implementation: () => () => randomUUID(),
});
Or when using the uuid package,
schema.registerFunction({
name: 'uuid_generate_v4',
returns: DataType.uuid,
implementation: () => v4
});