-
Notifications
You must be signed in to change notification settings - Fork 85
/
config.service.ts
119 lines (105 loc) 路 3.71 KB
/
config.service.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import { Inject, Injectable, Optional } from '@nestjs/common';
import get from 'lodash.get';
import has from 'lodash.has';
import set from 'lodash.set';
import { isUndefined } from 'util';
import {
CONFIGURATION_TOKEN,
VALIDATED_ENV_PROPNAME,
} from './config.constants';
import { NoInferType } from './types';
@Injectable()
export class ConfigService<K = Record<string, any>> {
get isCacheEnabled(): boolean {
return this._isCacheEnabled;
}
set isCacheEnabled(value: boolean) {
this._isCacheEnabled = value;
}
private readonly cache: Partial<K> = {} as any;
private _isCacheEnabled = false;
constructor(
@Optional()
@Inject(CONFIGURATION_TOKEN)
private readonly internalConfig: Record<string, any> = {},
) {}
/**
* Get a configuration value (either custom configuration or process environment variable)
* based on property path (you can use dot notation to traverse nested object, e.g. "database.host").
* It returns a default value if the key does not exist.
* @param propertyPath
* @param defaultValue
*/
get<T = any>(propertyPath: keyof K): T | undefined;
/**
* Get a configuration value (either custom configuration or process environment variable)
* based on property path (you can use dot notation to traverse nested object, e.g. "database.host").
* It returns a default value if the key does not exist.
* @param propertyPath
* @param defaultValue
*/
get<T = any>(propertyPath: keyof K, defaultValue: NoInferType<T>): T;
/**
* Get a configuration value (either custom configuration or process environment variable)
* based on property path (you can use dot notation to traverse nested object, e.g. "database.host").
* It returns a default value if the key does not exist.
* @param propertyPath
* @param defaultValue
*/
get<T = any>(propertyPath: keyof K, defaultValue?: T): T | undefined {
const validatedEnvValue = this.getFromValidatedEnv(propertyPath);
if (!isUndefined(validatedEnvValue)) {
return validatedEnvValue;
}
const processEnvValue = this.getFromProcessEnv(propertyPath, defaultValue);
if (!isUndefined(processEnvValue)) {
return processEnvValue;
}
const internalValue = this.getFromInternalConfig(propertyPath);
if (!isUndefined(internalValue)) {
return internalValue;
}
return defaultValue;
}
private getFromCache<T = any>(
propertyPath: keyof K,
defaultValue?: T,
): T | undefined {
const cachedValue = get(this.cache, propertyPath);
return isUndefined(cachedValue)
? defaultValue
: ((cachedValue as unknown) as T);
}
private getFromValidatedEnv<T = any>(propertyPath: keyof K): T | undefined {
const validatedEnvValue = get(
this.internalConfig[VALIDATED_ENV_PROPNAME],
propertyPath,
);
return (validatedEnvValue as unknown) as T;
}
private getFromProcessEnv<T = any>(
propertyPath: keyof K,
defaultValue: any,
): T | undefined {
if (
this.isCacheEnabled &&
has(this.cache as Record<any, any>, propertyPath)
) {
const cachedValue = this.getFromCache(propertyPath, defaultValue);
return !isUndefined(cachedValue) ? cachedValue : defaultValue;
}
const processValue = get(process.env, propertyPath);
this.setInCacheIfDefined(propertyPath, processValue);
return (processValue as unknown) as T;
}
private getFromInternalConfig<T = any>(propertyPath: keyof K): T | undefined {
const internalValue = get(this.internalConfig, propertyPath);
return internalValue;
}
private setInCacheIfDefined(propertyPath: keyof K, value: any): void {
if (typeof value === 'undefined') {
return;
}
set(this.cache as Record<any, any>, propertyPath, value);
}
}