Skip to content

Commit e829207

Browse files
authored
Dedup exact same selectors while keep original precedence (#31)
1 parent 33f033e commit e829207

File tree

7 files changed

+85
-37
lines changed

7 files changed

+85
-37
lines changed

src/AzureAppConfigurationImpl.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ import { AzureAppConfiguration } from "./AzureAppConfiguration";
66
import { AzureAppConfigurationOptions } from "./AzureAppConfigurationOptions";
77
import { IKeyValueAdapter } from "./IKeyValueAdapter";
88
import { JsonKeyValueAdapter } from "./JsonKeyValueAdapter";
9-
import { KeyFilter } from "./KeyFilter";
10-
import { LabelFilter } from "./LabelFilter";
9+
import { KeyFilter, LabelFilter } from "./types";
1110
import { AzureKeyVaultKeyValueAdapter } from "./keyvault/AzureKeyVaultKeyValueAdapter";
1211
import { CorrelationContextHeaderName } from "./requestTracing/constants";
1312
import { createCorrelationContextHeader, requestTracingEnabled } from "./requestTracing/utils";
13+
import { SettingSelector } from "./types";
1414

1515
export class AzureAppConfigurationImpl extends Map<string, unknown> implements AzureAppConfiguration {
1616
private adapters: IKeyValueAdapter[] = [];
@@ -109,12 +109,23 @@ export class AzureAppConfigurationImpl extends Map<string, unknown> implements A
109109
}
110110
}
111111

112-
function getValidSelectors(selectors?: { keyFilter: string, labelFilter?: string }[]) {
112+
function getValidSelectors(selectors?: SettingSelector[]) {
113113
if (!selectors || selectors.length === 0) {
114114
// Default selector: key: *, label: \0
115115
return [{ keyFilter: KeyFilter.Any, labelFilter: LabelFilter.Null }];
116116
}
117-
return selectors.map(selectorCandidate => {
117+
118+
// below code dedupes selectors by keyFilter and labelFilter, the latter selector wins
119+
const dedupedSelectors: SettingSelector[] = [];
120+
for (const selector of selectors) {
121+
const existingSelectorIndex = dedupedSelectors.findIndex(s => s.keyFilter === selector.keyFilter && s.labelFilter === selector.labelFilter);
122+
if (existingSelectorIndex >= 0) {
123+
dedupedSelectors.splice(existingSelectorIndex, 1);
124+
}
125+
dedupedSelectors.push(selector);
126+
}
127+
128+
return dedupedSelectors.map(selectorCandidate => {
118129
const selector = { ...selectorCandidate };
119130
if (!selector.keyFilter) {
120131
throw new Error("Key filter cannot be null or empty.");

src/AzureAppConfigurationOptions.ts

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,17 @@
33

44
import { AppConfigurationClientOptions } from "@azure/app-configuration";
55
import { AzureAppConfigurationKeyVaultOptions } from "./keyvault/AzureAppConfigurationKeyVaultOptions";
6+
import { SettingSelector } from "./types";
67

78
export const MaxRetries = 2;
89
export const MaxRetryDelayInMs = 60000;
910

1011
export interface AzureAppConfigurationOptions {
1112
/**
12-
* Specify what key-values to include in the configuration provider. include multiple sets of key-values
13-
*
14-
* @property keyFilter:
15-
* The key filter to apply when querying Azure App Configuration for key-values.
16-
* An asterisk `*` can be added to the end to return all key-values whose key begins with the key filter.
17-
* e.g. key filter `abc*` returns all key-values whose key starts with `abc`.
18-
* A comma `,` can be used to select multiple key-values. Comma separated filters must exactly match a key to select it.
19-
* Using asterisk to select key-values that begin with a key filter while simultaneously using comma separated key filters is not supported.
20-
* E.g. the key filter `abc*,def` is not supported. The key filters `abc*` and `abc,def` are supported.
21-
* For all other cases the characters: asterisk `*`, comma `,`, and backslash `\` are reserved. Reserved characters must be escaped using a backslash (\).
22-
* e.g. the key filter `a\\b\,\*c*` returns all key-values whose key starts with `a\b,*c`.
23-
*
24-
* @property labelFilter:
25-
* The label filter to apply when querying Azure App Configuration for key-values.
26-
* By default, the "null label" will be used, matching key-values without a label.
27-
* The characters asterisk `*` and comma `,` are not supported.
28-
* Backslash `\` character is reserved and must be escaped using another backslash `\`.
13+
* Specify what key-values to include in the configuration provider.
14+
* If no selectors are specified then all key-values with no label will be included.
2915
*/
30-
selectors?: { keyFilter: string, labelFilter?: string }[];
16+
selectors?: SettingSelector[];
3117

3218
/**
3319
* Specifies prefixes to be trimmed from the keys of all key-values retrieved from Azure App Configuration.

src/KeyFilter.ts

Lines changed: 0 additions & 6 deletions
This file was deleted.

src/LabelFilter.ts

Lines changed: 0 additions & 6 deletions
This file was deleted.

src/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,4 @@
33

44
export { load } from "./load";
55
export { AzureAppConfiguration } from "./AzureAppConfiguration";
6-
export { KeyFilter } from "./KeyFilter";
7-
export { LabelFilter } from "./LabelFilter";
6+
export { KeyFilter, LabelFilter } from "./types";

src/types.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT license.
3+
4+
/**
5+
* SettingSelector is used to select key-values from Azure App Configuration.
6+
* It is used to filter key-values based on keys and labels.
7+
*
8+
* @property keyFilter:
9+
* The key filter to apply when querying Azure App Configuration for key-values.
10+
* An asterisk `*` can be added to the end to return all key-values whose key begins with the key filter.
11+
* e.g. key filter `abc*` returns all key-values whose key starts with `abc`.
12+
* A comma `,` can be used to select multiple key-values. Comma separated filters must exactly match a key to select it.
13+
* Using asterisk to select key-values that begin with a key filter while simultaneously using comma separated key filters is not supported.
14+
* E.g. the key filter `abc*,def` is not supported. The key filters `abc*` and `abc,def` are supported.
15+
* For all other cases the characters: asterisk `*`, comma `,`, and backslash `\` are reserved. Reserved characters must be escaped using a backslash (\).
16+
* e.g. the key filter `a\\b\,\*c*` returns all key-values whose key starts with `a\b,*c`.
17+
*
18+
* @property labelFilter:
19+
* The label filter to apply when querying Azure App Configuration for key-values.
20+
* By default, the "null label" will be used, matching key-values without a label.
21+
* The characters asterisk `*` and comma `,` are not supported.
22+
* Backslash `\` character is reserved and must be escaped using another backslash `\`.
23+
*/
24+
export type SettingSelector = { keyFilter: string, labelFilter?: string };
25+
26+
/**
27+
* KeyFilter is used to filter key-values based on keys.
28+
*
29+
* @property Any:
30+
* Matches all key-values.
31+
*/
32+
export enum KeyFilter {
33+
Any = "*"
34+
}
35+
36+
/**
37+
* LabelFilter is used to filter key-values based on labels.
38+
*
39+
* @property Null:
40+
* Matches key-values without a label.
41+
*/
42+
export enum LabelFilter {
43+
Null = "\0"
44+
}

test/load.test.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,4 +151,24 @@ describe("load", function () {
151151
expect(settings.has("TestKey")).eq(true);
152152
expect(settings.get("TestKey")).eq("TestValueForProd");
153153
});
154-
})
154+
155+
it("should dedup exact same selectors but keeping the precedence", async () => {
156+
const connectionString = createMockedConnectionString();
157+
const settings = await load(connectionString, {
158+
selectors: [{
159+
keyFilter: "Test*",
160+
labelFilter: "Prod"
161+
}, {
162+
keyFilter: "Test*",
163+
labelFilter: "Test"
164+
}, {
165+
keyFilter: "Test*",
166+
labelFilter: "Prod"
167+
}]
168+
});
169+
expect(settings).not.undefined;
170+
expect(settings.has("TestKey")).eq(true);
171+
expect(settings.get("TestKey")).eq("TestValueForProd");
172+
});
173+
174+
});

0 commit comments

Comments
 (0)