Skip to content

Commit

Permalink
Feat(base config builder): allow async overrides (#2177)
Browse files Browse the repository at this point in the history
* feat(modules): allow async config builder overrides

Allow `_createConfig` method in `BaseConfigBuilder` to return `ObservableInput<TConfig>` instead of `Observable<TConfig>`. This enables more flexibility in how the config is created, as the method can return a Promise or other observable-like type.

* feat(BaseConfigBuilder): add methods to retrieve and check config callbacks

- Add `_get` method to retrieve the configuration callback for a given target path
- Add `_has` method to check if a target path exists in the configuration callbacks

* refactor(BaseConfigBuilder): enhance configuration builder

- Improve documentation and examples for BaseConfigBuilder
- Update type annotations and JSDoc comments for better type safety and clarity

* refactor(BaseConfigBuilder): add sealed and access modifiers

- Add `@sealed` decorator to public methods in `BaseConfigBuilder`
- Change access modifiers of some methods to `@protected`
  • Loading branch information
odinr authored May 22, 2024
1 parent f1eb628 commit fb424be
Show file tree
Hide file tree
Showing 4 changed files with 301 additions and 27 deletions.
29 changes: 29 additions & 0 deletions .changeset/allow-async-config-builder-overrides.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
"@equinor/modules": patch
---

## @equinor/modules

### Changes to `BaseConfigBuilder`

The `_createConfig` method in `BaseConfigBuilder` has been updated to return an `ObservableInput<TConfig>` instead of an `Observable<TConfig>`.
This allows for more flexibility in how the config is created, as the method can now return a Promise or other observable-like type.

Additionally, the `_createConfig` method now uses `from()` to convert the result of `_buildConfig` to an observable stream.

Here's an example of how the updated `_createConfig` method can be used:

```typescript
protected _createConfig(
init: ConfigBuilderCallbackArgs,
initial?: Partial<TConfig>
): ObservableInput<TConfig> {
return from(this._buildConfig(init, initial)).pipe(
mergeMap((config) => this._processConfig(config, init))
);
}
```

This change allows for asynchronous operations to be performed within the `_buildConfig` method, which can then be processed in the `_processConfig` method.

Consumers of the `BaseConfigBuilder` class should not need to update their code, as the public API remains the same.
20 changes: 20 additions & 0 deletions .changeset/improve-docs-baseconfig-builder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
"@equinor/fusion-framework": patch
---

## @equinor/fusion-framework

### Improved documentation for `BaseConfigBuilder`

The `BaseConfigBuilder` class has been updated with improved documentation to better explain its usage and capabilities.

#### What changed?

The `BaseConfigBuilder` class is an abstract class that provides a flexible and extensible way to build and configure modules. It allows you to define configuration callbacks for different parts of your module's configuration, and then combine and process these callbacks to generate the final configuration object.

The documentation has been expanded to include:

1. A detailed explanation of how the `BaseConfigBuilder` class is designed to be used, including an example of creating a configuration builder for a hypothetical `MyModule` module.
2. Descriptions of the key methods and properties provided by the `BaseConfigBuilder` class, such as `createConfig`, `createConfigAsync`, `_set`, `_buildConfig`, and `_processConfig`.
3. Guidance on how to override the `_processConfig` method to add additional logic or validation to the configuration object before it is returned.
4. Examples of how to use the `BaseConfigBuilder` class to handle common configuration scenarios, such as setting default values or validating configuration properties.
50 changes: 50 additions & 0 deletions .changeset/improve-extendability-config-builder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
"@equinor/modules": patch
---

## @equinor/modules

### Changes to `BaseConfigBuilder`

The `BaseConfigBuilder` class has been updated to improve its extendability and provide better access to the internal configuration callbacks.

#### Added `_get` and `_has` methods

Two new protected methods have been added to the `BaseConfigBuilder` class:

1. `_get<TTarget extends DotPath<TConfig>>(target: TTarget)`: This method retrieves the configuration callback for the specified target path in the configuration. It returns the callback or `undefined` if no callback is registered for the given target.

2. `_has<TTarget extends DotPath<TConfig>>(target: TTarget)`: This method checks if the given target path exists in the configuration callbacks. It returns `true` if the target path exists, `false` otherwise.

These methods allow subclasses of `BaseConfigBuilder` to easily access and check the existence of configuration callbacks for specific targets.

#### Example usage

Suppose you have a subclass of `BaseConfigBuilder` called `MyConfigBuilder`. You can use the new `_get` and `_has` methods like this:

```typescript
class MyConfigBuilder extends BaseConfigBuilder<MyConfig> {
// override the _buildConfig method
async _createConfig(
init: ConfigBuilderCallbackArgs,
initial?: Partial<TConfig>,
): ObservableInput<TConfig> {
// Check if a callback is registered for the'my.custom.config' target
if (this._has('my.custom.config')) {
// register a fallback value for the'my.custom.config' target if no callback is registered
this._set('my.custom.config', async() => { return 42; });
} else {
// if a callback is registered, call it and log the result
configCallback = this._get('my.custom.config');
configValue$ = from(configCallback(init, initial));
console.log(await lastValueFrom(configValue$));
}
return lastValueFrom(from(super._createConfig(init, initial)));
}
}
```

> [!WARNING]
> the example code is not intended to be a working implementation of the `MyConfigBuilder` class. It is only intended to demonstrate how the new `_get` and `_has` methods can be used.
This change allows for more flexibility and easier extensibility of the `BaseConfigBuilder` class.
Loading

0 comments on commit fb424be

Please sign in to comment.