Refactor executable IDs to use strings #262
This commit unifies executable ID structure across categories and scripts, paving the way for more complex ID solutions for #262. It also refactors related code to adapt to the changes. Key changes: - Change numeric IDs to string IDs for categories - Use named types for string IDs to improve code clarity - Add unit tests to verify ID uniqueness Other supporting changes: - Separate concerns in entities for data access and executables by using separate abstractions (`Identifiable` and `RepositoryEntity`) - Simplify usage and construction of entities. - Remove `BaseEntity` for simplicity. - Move creation of categories/scripts to domain layer - Refactor CategoryCollection for better validation logic isolation - Rename some categories to keep the names (used as pseudo-IDs) unique on Windows.
This commit is contained in:
@@ -1,14 +0,0 @@
|
||||
import { isNumber } from '@/TypeHelpers';
|
||||
import type { IEntity } from './IEntity';
|
||||
|
||||
export abstract class BaseEntity<TId> implements IEntity<TId> {
|
||||
protected constructor(public id: TId) {
|
||||
if (!isNumber(id) && !id) {
|
||||
throw new Error('Id cannot be null or empty');
|
||||
}
|
||||
}
|
||||
|
||||
public equals(otherId: TId): boolean {
|
||||
return this.id === otherId;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
/** Aggregate root */
|
||||
export interface IEntity<TId> {
|
||||
id: TId;
|
||||
equals(other: TId): boolean;
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
import type { Repository } from '../../application/Repository/Repository';
|
||||
import type { IEntity } from '../Entity/IEntity';
|
||||
import type { RepositoryEntity, RepositoryEntityId } from '../../application/Repository/RepositoryEntity';
|
||||
|
||||
export class InMemoryRepository<TKey, TEntity extends IEntity<TKey>>
|
||||
implements Repository<TKey, TEntity> {
|
||||
export class InMemoryRepository<TEntity extends RepositoryEntity>
|
||||
implements Repository<TEntity> {
|
||||
private readonly items: TEntity[];
|
||||
|
||||
constructor(items?: TEntity[]) {
|
||||
this.items = items ?? new Array<TEntity>();
|
||||
constructor(items?: readonly TEntity[]) {
|
||||
this.items = new Array<TEntity>();
|
||||
if (items) {
|
||||
this.items.push(...items);
|
||||
}
|
||||
}
|
||||
|
||||
public get length(): number {
|
||||
@@ -17,7 +20,7 @@ implements Repository<TKey, TEntity> {
|
||||
return predicate ? this.items.filter(predicate) : this.items;
|
||||
}
|
||||
|
||||
public getById(id: TKey): TEntity {
|
||||
public getById(id: RepositoryEntityId): TEntity {
|
||||
const items = this.getItems((entity) => entity.id === id);
|
||||
if (!items.length) {
|
||||
throw new Error(`missing item: ${id}`);
|
||||
@@ -39,7 +42,7 @@ implements Repository<TKey, TEntity> {
|
||||
this.items.push(item);
|
||||
}
|
||||
|
||||
public removeItem(id: TKey): void {
|
||||
public removeItem(id: RepositoryEntityId): void {
|
||||
const index = this.items.findIndex((item) => item.id === id);
|
||||
if (index === -1) {
|
||||
throw new Error(`Cannot remove (id: ${id}) as it does not exist`);
|
||||
@@ -47,7 +50,7 @@ implements Repository<TKey, TEntity> {
|
||||
this.items.splice(index, 1);
|
||||
}
|
||||
|
||||
public exists(id: TKey): boolean {
|
||||
public exists(id: RepositoryEntityId): boolean {
|
||||
const index = this.items.findIndex((item) => item.id === id);
|
||||
return index !== -1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user