Skip to content

Commit

Permalink
refactoring: overall clean up (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
akdasa authored Dec 3, 2022
1 parent b43ee0d commit d7fe0e2
Show file tree
Hide file tree
Showing 31 changed files with 263 additions and 178 deletions.
16 changes: 7 additions & 9 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,14 @@ class CalculatorContext {
## Command
Command is an object that represents a single action. It is used to encapsulate the data needed to perform an action.

`IComannd` is a generic interface that takes two parameters: `TContext` and `TResult`. `TContext` is a type of context that will be used to execute the command. `TResult` is a type of result that will be returned after command execution.
`Comannd` is a generic interface that takes two parameters: `TContext` and `TResult`. `TContext` is a type of context that will be used to execute the command. `TResult` is a type of result that will be returned after command execution.

`ICommand` has two methods: `execute` and `revert`. You should not execute the command directly. You should use `Processor` to execute the command.
`Command` has two methods: `execute` and `revert`. You should not execute the command directly. You should use `Processor` to execute the command.

```ts
import { ICommand } from '@akdasa-studios/framework/commands'
import { Result } from '@akdasa-studios/framework/core'
import { Command, Result } from '@akdasa-studios/framework'


class AddCommand implements ICommand<CalculatorContext, Result<void, string>> {
class AddCommand implements Command<CalculatorContext, Result<void, string>> {
constructor(private value: number) {}
public execute(context: CalculatorContext) {
context.set(context.value + this.value)
Expand All @@ -56,12 +54,12 @@ class AddCommand implements ICommand<CalculatorContext, Result<void, string>> {
```

## Processor
`Processor` is an object that executes commands. `Processor` has a method `execute` that takes a command and executes it. It raises an error if command was executed before. So you cannot execute the same command twice. You have to create a new command instance.
`Processor` is an object that executes commands. `Processor` has a method `execute` that takes a command and executes it. It returns failure result if command was executed before. So you cannot execute the same command twice. You have to create a new command instance.

`Processor` has a method `revert` that reverts last executed command. It raises an error if there is no command to revert.
`Processor` has a method `revert` that reverts last executed command. It returns failre result if there is no command to revert.

```ts
import { Processor } from '@akdasa-studios/framework/commands'
import { Processor } from '@akdasa-studios/framework'

const state = new ApplicationState()
const context = new CalculatorContext(state)
Expand Down
12 changes: 9 additions & 3 deletions lib/commands/command.ts → lib/commands/Command.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { AnyResult } from '@lib/core'


/**
* Command is the base class for all commands.
*/
export interface ICommand<
export interface Command<
TContext,
TResult extends AnyResult
> {
Expand All @@ -13,10 +14,15 @@ export interface ICommand<
* @returns The result of the command.
*/
execute(context: TContext): TResult
revert(context: TContext): void

/**
* Reverts the command.
* @param context The context in which the command is reverted.
*/
revert(context: TContext)
}

/**
* Any command that can be executed.
*/
export type AnyCommand = ICommand<unknown, AnyResult>
export type AnyCommand = Command<unknown, AnyResult>
79 changes: 79 additions & 0 deletions lib/commands/Processor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { AnyResult, Fail, NoResult, Ok, Result } from '@lib/core'
import { Command, AnyCommand } from './Command'


export class ProcessorResult<TCommandResult extends AnyResult> {
constructor(
public readonly processorResult: Result<boolean, string>,
public readonly commandResult: TCommandResult = NoResult as TCommandResult,
) {}

/**
* Indicates if the command is executed.
* @returns True if the command is executed, otherwise false.
* @note This property is true if the command is executed successfully or failed.
*/
get isCommandExecuted(): boolean {
return this.processorResult.isSuccess
}

/**
* Indicates if the command is executed successfully.
* @returns True if the command is executed successfully, otherwise false.
*/
get isCommandSucceeded(): boolean {
return this.commandResult.isSuccess
}

/**
* Gets the result of the executed command.
* @returns {TCommandResult['value']} Returns the result of the executed command.
*/
get value() : TCommandResult['value'] | TCommandResult['error'] {
return this.commandResult.value
}
}

/**
* Processor executes commands.
*/
export class Processor<TContext> {
private stack: AnyCommand[] = []

/**
* Initialize a new instance of the Processor class.
* @param context Context of the processor.
*/
constructor(
public readonly context: TContext
) { }

/**
* Excecute the command.
* @param command Command to process.
* @returns {ProcessorResult<TResult>} Returns the result execution.
*/
execute<TResult extends AnyResult>(
command: Command<TContext, TResult>
): ProcessorResult<TResult> {
if (this.stack.includes(command)) {
return new ProcessorResult(Fail('Command is already executed.'))
}
this.stack.push(command)
const commandResult = command.execute(this.context)
return new ProcessorResult<TResult>(Ok(), commandResult)
}

/**
* Revert the last executed command.
*/
revert<TResult extends AnyResult>(): ProcessorResult<TResult> {
const command = this.stack.pop()
if (!command) {
return new ProcessorResult(Fail('No command to revert.'))
}

const commandResult = command.revert(this.context)
return new ProcessorResult<TResult>(Ok(), commandResult)
}
}
4 changes: 2 additions & 2 deletions lib/commands/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { ICommand } from './command'
export { Processor } from './processor'
export * from './Command'
export * from './Processor'
37 changes: 0 additions & 37 deletions lib/commands/processor.ts

This file was deleted.

26 changes: 15 additions & 11 deletions lib/core/result.ts → lib/core/Result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ export type AnyResult = Result<unknown, unknown>
*/
export class Result<
TSuccess = void,
TFail = string
> implements Result<TSuccess, TFail> {
TFailure = string
> implements Result<TSuccess, TFailure> {
private readonly _success: boolean
private readonly _payload: TSuccess | TFail | undefined
private readonly _payload: TSuccess | TFailure | undefined

/**
* Initializes a new instance of the Result class.
Expand All @@ -21,7 +21,7 @@ export class Result<
*/
private constructor(
success: boolean,
payload: TSuccess | TFail | undefined,
payload: TSuccess | TFailure | undefined,
) {
this._success = success
this._payload = payload
Expand All @@ -43,10 +43,10 @@ export class Result<
* @param payload The payload of the result.
* @returns A new instance of the Result class.
*/
public static fail<TSuccessPayload, TFailPayload>(
payload?: TFailPayload
): Result<TSuccessPayload, TFailPayload> {
return new Result<TSuccessPayload, TFailPayload>(false, payload)
public static fail<TSuccessPayload, TFailurePayload>(
payload?: TFailurePayload
): Result<TSuccessPayload, TFailurePayload> {
return new Result<TSuccessPayload, TFailurePayload>(false, payload)
}

/**
Expand Down Expand Up @@ -77,7 +77,11 @@ export class Result<
* Gets the payload of the result.
* @returns The payload of the result.
*/
get error(): TFail {
return this._payload as TFail
get error(): TFailure {
return this._payload as TFailure
}
}
}

export const Ok = Result.ok
export const Fail = Result.fail
export const NoResult: Result<void, void> = Result.ok<void, void>(undefined)
2 changes: 1 addition & 1 deletion lib/core/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from './result'
export * from './Result'
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Entity } from './entity'
import { Identity } from './identity'
import { Entity } from './Entity'
import { Identity } from './Identity'


/**
Expand Down
12 changes: 12 additions & 0 deletions lib/domain/models/Builder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Result } from '@lib/core'

/**
* Builds a new instance of the specified type or returns a failure result.
*/
export abstract class Builder<TModel, TError> {
/**
* Builds a new instance of the specified type or returns a failure result.
* @returns A new instance of the specified type or a failure result.
*/
public abstract build(): Result<TModel, TError>
}
8 changes: 4 additions & 4 deletions lib/domain/models/entity.ts → lib/domain/models/Entity.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Identity } from './identity'
import { IEqualable, IIdentifiable } from './interfaces'
import { Identity } from './Identity'
import { Equalable, Identifiable } from './Interfaces'


/**
Expand All @@ -8,8 +8,8 @@ import { IEqualable, IIdentifiable } from './interfaces'
export abstract class Entity<
TIdentity extends Identity<unknown, unknown>
> implements
IIdentifiable<TIdentity>,
IEqualable<Entity<TIdentity>>
Identifiable<TIdentity>,
Equalable<Entity<TIdentity>>
{
private _identity: TIdentity

Expand Down
File renamed without changes.
18 changes: 18 additions & 0 deletions lib/domain/models/Interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Identity } from './Identity'


/**
* Identifiable is an interface for all objects that have an identity.
*/
export interface Identifiable<
TIdentity extends Identity<unknown, unknown>
> {
get id(): TIdentity
}

/**
* Equalable is an interface for all objects that can be compared for equality.
*/
export interface Equalable<T> {
equals(other: T): boolean
}
5 changes: 2 additions & 3 deletions lib/domain/models/value.ts → lib/domain/models/Value.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// import { IEqualable } from './interfaces'
import { Equalable } from './Interfaces'

export class Value<TValueType> {
// implements IEqualable<Value<TValueType>> {
export class Value<TValueType> implements Equalable<Value<TValueType>> {
/**
* Equality check of two values
* @param value Value to compare to
Expand Down
5 changes: 0 additions & 5 deletions lib/domain/models/builder.ts

This file was deleted.

12 changes: 6 additions & 6 deletions lib/domain/models/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export * from './aggregate'
export * from './builder'
export * from './entity'
export * from './identity'
export * from './interfaces'
export * from './value'
export * from './Aggregate'
export * from './Builder'
export * from './Entity'
export * from './Identity'
export * from './Interfaces'
export * from './Value'
18 changes: 0 additions & 18 deletions lib/domain/models/interfaces.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Aggregate, AnyIdentity } from '@lib/domain/models'
import { IRepository } from './repository'
import { Predicate, Query, Expression, Binding, Operators, LogicalOperators } from './query'
import { Repository } from './Repository'
import { Predicate, Query, Expression, Binding, Operators, LogicalOperators } from './Query'


export abstract class InMemoryRepository<
TEntity extends Aggregate<AnyIdentity>
> implements IRepository<TEntity> {
> implements Repository<TEntity> {
protected entities = new Map<TEntity['id'], TEntity>()
protected processor = new InMemoryQueryProcessor<TEntity>()

Expand Down
1 change: 0 additions & 1 deletion lib/persistence/query.ts → lib/persistence/Query.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Aggregate, AnyIdentity } from '@lib/domain/models'


/**
* Comparison operators. These are used to compare a field with a value.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Query } from '@lib/persistence'
/**
* Interface for a repository.
*/
export interface IRepository<
export interface Repository<
TEntity extends Aggregate<AnyIdentity>
> {
/**
Expand Down
6 changes: 3 additions & 3 deletions lib/persistence/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from './query'
export * from './repository'
export * from './inmemory-repository'
export * from './Query'
export * from './Repository'
export * from './InMemoryRepository'
Loading

0 comments on commit d7fe0e2

Please sign in to comment.