41 lines
2.3 KiB
TypeScript
41 lines
2.3 KiB
TypeScript
import { EntityProperty, EventArgs, EventSubscriber } from '@mikro-orm/core';
|
|
|
|
/**
|
|
* The tests are ran on an in-memory SQLite database. However, SQLite does not allow fields which are part of composite
|
|
* primary keys to be autoincremented (while PostgreSQL, which we use in production, does). This Subscriber works around
|
|
* the issue by remembering the highest values for every autoincremented part of a primary key and assigning them when
|
|
* creating a new entity.
|
|
*
|
|
* However, it is important to note the following limitations:
|
|
* - this class can only be used for in-memory SQLite databases since the information on what the highest sequence
|
|
* number for each of the properties is, is only saved transiently.
|
|
* - automatically setting the generated "autoincremented" value for properties only works when the entity is created
|
|
* via an entityManager.create(...) or repo.create(...) method. Otherwise, onInit will not be called and therefore,
|
|
* the sequence number will not be filled in.
|
|
*/
|
|
export class SqliteAutoincrementSubscriber implements EventSubscriber {
|
|
private sequenceNumbersForEntityType = new Map<string, number>();
|
|
|
|
/**
|
|
* When an entity with an autoincremented property which is part of the composite private key is created,
|
|
* automatically fill this property so we won't face not-null-constraint exceptions when persisting it.
|
|
*/
|
|
onInit<T extends object>(args: EventArgs<T>): void {
|
|
if (!args.meta.compositePK) {
|
|
return; // If there is not a composite primary key, autoincrement works fine with SQLite anyway.
|
|
}
|
|
|
|
for (const prop of Object.values(args.meta.properties)) {
|
|
const property = prop as EntityProperty<T>;
|
|
if (property.primary && property.autoincrement && (args.entity as Record<string, unknown>)[property.name] === undefined) {
|
|
// Obtain and increment sequence number of this entity.
|
|
const propertyKey = args.meta.class.name + '.' + property.name;
|
|
const nextSeqNumber = this.sequenceNumbersForEntityType.get(propertyKey) || 0;
|
|
this.sequenceNumbersForEntityType.set(propertyKey, nextSeqNumber + 1);
|
|
|
|
// Set the property accordingly.
|
|
(args.entity as Record<string, unknown>)[property.name] = nextSeqNumber + 1;
|
|
}
|
|
}
|
|
}
|
|
}
|