Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DeepPartial } from '@vendure/common/lib/shared-types';
import { Column, Entity, JoinColumn, OneToOne } from 'typeorm';
import { Column, Entity, JoinColumn, OneToOne, Unique } from 'typeorm';

import { SoftDeletable } from '../../common/types/common-types';
import { HasCustomFields } from '../../config/custom-field/custom-field-types';
Expand All @@ -16,6 +16,7 @@ import { User } from '../user/user.entity';
* @docsCategory entities
*/
@Entity()
@Unique(['emailAddress', 'isCurrent'])
export class Administrator extends VendureEntity implements SoftDeletable, HasCustomFields {
constructor(input?: DeepPartial<Administrator>) {
super(input);
Expand All @@ -28,9 +29,12 @@ export class Administrator extends VendureEntity implements SoftDeletable, HasCu

@Column() lastName: string;

@Column({ unique: true })
@Column()
emailAddress: string;

@Column({ type: 'boolean', default: true, nullable: true })
isCurrent: true | null;
Comment on lines +35 to +36
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Verify type safety: TypeScript true | null vs SQL boolean.

The TypeScript type is true | null, but the column type is boolean. This mismatch could cause issues:

  • SQL boolean columns can store true, false, or null
  • If the database ever returns false (through direct DB manipulation or ORM behavior), TypeScript will not expect it
  • TypeScript will show type errors when assigning boolean values to this field

Consider using boolean | null for better type safety, and enforce the constraint through validation logic or a database CHECK constraint if you truly want to prevent false values.

If you want to keep the current pattern, add a comment explaining why only true and null are valid values.

+    // isCurrent can only be true (for active administrators) or null (for soft-deleted ones)
+    // This constraint allows multiple soft-deleted administrators with the same email address
     @Column({ type: 'boolean', default: true, nullable: true })
     isCurrent: true | null;
🤖 Prompt for AI Agents
In packages/core/src/entity/administrator/administrator.entity.ts around lines
35-36, the property is declared as TypeScript type `true | null` while the
Column is defined as SQL `boolean`; change the TS type to `boolean | null` to
match the database semantics (allow true, false, or null) or, if you truly
require only true/null, keep `true | null` but add a clear inline comment
explaining the restriction and add application-level validation or a DB CHECK
constraint to prevent false values; ensure any code that sets/reads this field
is updated to the chosen type/validation approach.


@OneToOne(type => User)
@JoinColumn()
user: User;
Expand Down
4 changes: 3 additions & 1 deletion packages/core/src/service/services/administrator.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,9 @@ export class AdministratorService {
if (isSoleSuperadmin) {
throw new InternalServerError('error.cannot-delete-sole-superadmin');
}
await this.connection.getRepository(ctx, Administrator).update({ id }, { deletedAt: new Date() });
await this.connection
.getRepository(ctx, Administrator)
.update({ id }, { isCurrent: null, deletedAt: new Date() });
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
await this.userService.softDelete(ctx, administrator.user.id);
await this.eventBus.publish(new AdministratorEvent(ctx, administrator, 'deleted', id));
Expand Down