Partial Indexes not working with unique index where column value is null
See original GitHub issueI saw in this issue that support for Partial Indexes was added: https://github.com/oguimbal/pg-mem/issues/89
However, if you insert null as a value for a column with a unique index, in actual postgres it works since null values are not considered in unique value validation, but pg-mem does appear to include them when validating uniques and prevents the 2nd row from inserting with a value of null.
Example SQL for postgres (works as expected against an actual postgres engine)
create table "test_table" (
"id" character varying(36) NOT NULL,
"unique_data" character varying(36),
"deleted_at" timestamp without time zone,
CONSTRAINT "PK_test_table_id"
PRIMARY KEY ("id")
);
CREATE UNIQUE INDEX "UXtest_table_unique_data" ON "public"."test_table" ("unique_data") WHERE deleted_at IS NULL;
insert into test_table ("id", "unique_data", "deleted_at") VALUES('1', default, default );
insert into test_table ("id", "unique_data", "deleted_at") VALUES('2', default, default );
Example jest / nestjs / typeorm / pg-mem test (NOT WORKING but I’d expect it to)
// "@nestjs/testing": "^8.0.0",
import { Test, TestingModule } from '@nestjs/testing';
// "@nestjs/typeorm": "^8.0.2",
import { getRepositoryToken } from '@nestjs/typeorm';
// "typeorm": "^0.2.37",
import { Repository, Connection, Entity,
Column,
PrimaryColumn,
Index,
DeleteDateColumn,
} from 'typeorm';
// "pg-mem": "^2.0.2",
import { newDb } from 'pg-mem';
@Index('UXtest_table_unique_data', ['uniqueData'], {
unique: true,
where: 'deleted_at IS NULL'
})
@Entity()
export class TestEntity {
@PrimaryColumn({ length: 36 })
id: string;
@Column({ length: 36, name: 'unique_data', nullable: true })
uniqueData?: string;
@DeleteDateColumn({
name: 'deleted_at',
type: 'timestamp without time zone',
nullable: true,
})
deletedAt: Date;
}
describe('ExamplePartialUniqueProblemWithPgMem', () => {
let testRepo: Repository<TestEntity>, connection: Connection;
beforeEach(async () => {
// create a postgres memory db
const db = newDb({});
// define current_database
// work around typeorm calling 'current_database' function
db.public.registerFunction({
implementation: () => 'test',
name: 'current_database',
});
// create a Typeorm connection
connection = await db.adapters.createTypeormConnection({
type: 'postgres',
entities: [TestEntity],
});
// create tables
await connection.synchronize();
testRepo = connection.getRepository(TestEntity);
});
afterEach(async () => {
await connection.close();
});
it('create 2 test entries will null for a unique column', async () => {
await testRepo.save({
id: '1',
});
await testRepo.save({
id: '2',
});
// get id 2
const record2 = await testRepo.findOne('2');
expect(record2.id).toEqual('2');
});
});
Running this test produces this output for me
npm run test -- test.spec
> test@0.0.1 test
> jest --testResultsProcessor=jest-junit "test.spec"
FAIL src/talent/test.spec.ts (8.483 s)
ExamplePartialUniqueProblemWithPgMem
✕ create 2 test entries will null for a unique column (241 ms)
● ExamplePartialUniqueProblemWithPgMem › create 2 test entries will null for a unique column
QueryFailedError: ERROR: insert into "test_entity" (id, unique_data, deleted_at) values ($1, $2, $3) returning "unique_data" - duplicate key value violates unique constraint "test_entity_pkey"
DETAIL: Key (unique_data)=() 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 "test_entity"("id", "unique_data", "deleted_at") VALUES ('2', DEFAULT, DEFAULT) RETURNING "deleted_at";
👉 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 QueryFailedError.TypeORMError [as constructor] (error/TypeORMError.ts:7:9)
at new QueryFailedError (error/QueryFailedError.ts:9:9)
at PostgresQueryRunner.<anonymous> (driver/postgres/PostgresQueryRunner.ts:258:19)
at step (../node_modules/tslib/tslib.js:143:27)
at Object.throw (../node_modules/tslib/tslib.js:124:57)
at rejected (../node_modules/tslib/tslib.js:115:69)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 8.542 s, estimated 9 s
Ran all test suites matching /test.spec/i.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
Issue Analytics
- State:
- Created 2 years ago
- Reactions:1
- Comments:6 (4 by maintainers)
Top Results From Across the Web
Postgres partial index on IS NULL not working
As mentioned above, I am trying to drop the state column so I want to be able to fetch the same rows using...
Read more >Can't create a unique index that ignores nulls in MongoDB
To use the partial index, a query must contain the filter expression (or a modified filter expression that specifies a subset of the...
Read more >Documentation: 15: 11.8. Partial Indexes - PostgreSQL
A partial index is an index built over a subset of a table; the subset is defined by a conditional expression (called the...
Read more >Unique index in mongoDB 3.2 ignoring null values
The problem is Sparse indexes can't be used with the Partial index. Also, adding unique indexes, adds the null value to the index...
Read more >Partial Indexes - SQLite
A partial index is an index over a subset of the rows of a table. In ordinary indexes, there is exactly one entry...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found

Confirmed fixed!
I’ll test it out, thanks for the fast followup!