@synet/patterns
Version:
Robust, battle-tested collection of stable patterns used in Synet packages
179 lines (178 loc) • 5.51 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Result = void 0;
/**
* A simple and versatile Result pattern implementation
* Used for representing the outcome of operations that might fail
*/
class Result {
constructor(_isSuccess, _value, _error) {
this._isSuccess = _isSuccess;
this._value = _value;
this._error = _error;
}
/**
* Returns whether this Result represents a successful operation
*/
get isSuccess() {
return this._isSuccess;
}
/**
* Returns whether this Result represents a failed operation
*/
get isFailure() {
return !this._isSuccess;
}
/**
* Returns the success value
* @throws Error if called on a failed result
*/
get value() {
if (!this.isSuccess) {
throw new Error("Cannot get value from a failed result");
}
return this._value;
}
/**
* Returns the error details if this is a failure result
*/
get error() {
return this._error;
}
/**
* Returns the error message if this is a failure result
*/
get errorMessage() {
return this._error?.message;
}
/**
* Returns the error cause if this is a failure result
*/
get errorCause() {
return this._error?.cause;
}
/**
* Creates a successful result with a value
* @param value The success value
*/
static success(value) {
return new Result(true, value);
}
/**
* Creates a failure result with a message, optional cause, and optional context data
* @param message Error message describing what went wrong
* @param cause Optional underlying error that caused the failure
* @param data Optional additional context data for debugging
*/
static fail(message, cause, ...data) {
return new Result(false, undefined, {
message,
cause,
data: data.length > 0 ? data : undefined,
});
}
/**
* Executes the given callback if this is a success result
* @param fn Function to execute with the success value
* @returns This result, for method chaining
*/
onSuccess(fn) {
if (this.isSuccess) {
fn(this.value);
}
return this;
}
/**
* Executes the given callback if this is a failure result
* @param fn Function to execute with the error details
* @returns This result, for method chaining
*/
onFailure(fn) {
if (this.isFailure && this._error) {
fn(this._error.message, this._error.cause, this._error.data);
}
return this;
}
/**
* Maps a successful result to another type using the provided function
* @param fn Mapping function to apply to the success value
* @returns A new Result with either the mapped value or the original error
*/
map(fn) {
if (this.isSuccess) {
return Result.success(fn(this.value));
}
return Result.fail(this._error?.message || "Unknown error", this._error?.cause, ...(this._error?.data || []));
}
/**
* Maps a successful result to another Result using the provided function
* @param fn Mapping function that returns a new Result
* @returns The new Result or the original error
*/
flatMap(fn) {
if (this.isSuccess) {
return fn(this.value);
}
return Result.fail(this._error?.message || "Unknown error", this._error?.cause, ...(this._error?.data || []));
}
/**
* Recovers from a failure by providing a default value
* @param defaultValue Value to use if this result is a failure
* @returns A success result with either the original or default value
*/
recover(defaultValue) {
if (this.isSuccess) {
return this;
}
return Result.success(defaultValue);
}
/**
* Attempts to recover from a failure by calling a function
* @param fn Function that provides a recovery value
* @returns A success result with either the original or recovered value
*/
recoverWith(fn) {
if (this.isSuccess) {
return this;
}
return Result.success(fn(this._error));
}
/**
* Ensures a condition is met or fails with the provided message
* @param condition Predicate that must be true
* @param message Error message if condition fails
* @returns This result if successful and condition is met, otherwise a failure
*/
ensure(condition, message) {
if (!this.isSuccess) {
return this;
}
return condition(this.value) ? this : Result.fail(message);
}
/**
* Checks if the result is null
* @returns true if the result is null, false otherwise
* */
isNull() {
return this.isSuccess && this.value === null;
}
combine(results) {
const errors = [];
const values = [];
for (const result of results) {
if (result.isFailure) {
if (result.error) {
errors.push(result.error);
}
}
else {
values.push(result.value);
}
}
if (errors.length > 0) {
return Result.fail("One or more results failed", undefined, ...errors);
}
return Result.success(values);
}
}
exports.Result = Result;