mirror of
https://github.com/Unleash/unleash.git
synced 2025-06-23 01:16:27 +02:00
fix: add sort to deep diff (#5084)
Sort array items before running compare. Feature flag certain properties of strategy that were previously not present in the /api/admin/features endpoint.
This commit is contained in:
parent
1f8d12bcdc
commit
cd864ed09e
@ -123,6 +123,8 @@
|
|||||||
"knex": "^2.4.2",
|
"knex": "^2.4.2",
|
||||||
"lodash.get": "^4.4.2",
|
"lodash.get": "^4.4.2",
|
||||||
"lodash.groupby": "^4.6.0",
|
"lodash.groupby": "^4.6.0",
|
||||||
|
"lodash.isequal": "^4.5.0",
|
||||||
|
"lodash.sortby": "^4.7.0",
|
||||||
"log4js": "^6.0.0",
|
"log4js": "^6.0.0",
|
||||||
"make-fetch-happen": "^11.0.0",
|
"make-fetch-happen": "^11.0.0",
|
||||||
"memoizee": "^0.4.15",
|
"memoizee": "^0.4.15",
|
||||||
|
@ -49,7 +49,12 @@ export const createStores = (
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
eventStore,
|
eventStore,
|
||||||
featureToggleStore: new FeatureToggleStore(db, eventBus, getLogger),
|
featureToggleStore: new FeatureToggleStore(
|
||||||
|
db,
|
||||||
|
eventBus,
|
||||||
|
getLogger,
|
||||||
|
config.flagResolver,
|
||||||
|
),
|
||||||
featureTypeStore: new FeatureTypeStore(db, getLogger),
|
featureTypeStore: new FeatureTypeStore(db, getLogger),
|
||||||
strategyStore: new StrategyStore(db, getLogger),
|
strategyStore: new StrategyStore(db, getLogger),
|
||||||
clientApplicationsStore: new ClientApplicationsStore(
|
clientApplicationsStore: new ClientApplicationsStore(
|
||||||
|
@ -157,6 +157,7 @@ export const deferredExportImportTogglesService = (
|
|||||||
db,
|
db,
|
||||||
eventBus,
|
eventBus,
|
||||||
getLogger,
|
getLogger,
|
||||||
|
flagResolver,
|
||||||
);
|
);
|
||||||
const tagStore = new TagStore(db, eventBus, getLogger);
|
const tagStore = new TagStore(db, eventBus, getLogger);
|
||||||
const tagTypeStore = new TagTypeStore(db, eventBus, getLogger);
|
const tagTypeStore = new TagTypeStore(db, eventBus, getLogger);
|
||||||
|
@ -5,12 +5,19 @@ import {
|
|||||||
FeatureToggle,
|
FeatureToggle,
|
||||||
IFeatureToggleQuery,
|
IFeatureToggleQuery,
|
||||||
ITag,
|
ITag,
|
||||||
|
IFlagResolver,
|
||||||
} from '../../../types';
|
} from '../../../types';
|
||||||
|
|
||||||
import { mapValues, ensureStringValue } from '../../../util';
|
import { mapValues, ensureStringValue } from '../../../util';
|
||||||
import { FeatureConfigurationClient } from '../types/feature-toggle-strategies-store-type';
|
import { FeatureConfigurationClient } from '../types/feature-toggle-strategies-store-type';
|
||||||
|
|
||||||
export class FeatureToggleRowConverter {
|
export class FeatureToggleRowConverter {
|
||||||
|
private flagResolver: IFlagResolver;
|
||||||
|
|
||||||
|
constructor(flagResolver: IFlagResolver) {
|
||||||
|
this.flagResolver = flagResolver;
|
||||||
|
}
|
||||||
|
|
||||||
isUnseenStrategyRow = (
|
isUnseenStrategyRow = (
|
||||||
feature: PartialDeep<IFeatureToggleClient>,
|
feature: PartialDeep<IFeatureToggleClient>,
|
||||||
row: Record<string, any>,
|
row: Record<string, any>,
|
||||||
@ -63,7 +70,9 @@ export class FeatureToggleRowConverter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
rowToStrategy = (row: Record<string, any>): IStrategyConfig => {
|
rowToStrategy = (row: Record<string, any>): IStrategyConfig => {
|
||||||
const strategy: IStrategyConfig = {
|
let strategy: IStrategyConfig;
|
||||||
|
if (this.flagResolver.isEnabled('playgroundImprovements')) {
|
||||||
|
strategy = {
|
||||||
id: row.strategy_id,
|
id: row.strategy_id,
|
||||||
name: row.strategy_name,
|
name: row.strategy_name,
|
||||||
title: row.strategy_title,
|
title: row.strategy_title,
|
||||||
@ -72,6 +81,16 @@ export class FeatureToggleRowConverter {
|
|||||||
sortOrder: row.sort_order,
|
sortOrder: row.sort_order,
|
||||||
disabled: row.strategy_disabled,
|
disabled: row.strategy_disabled,
|
||||||
};
|
};
|
||||||
|
} else {
|
||||||
|
strategy = {
|
||||||
|
id: row.strategy_id,
|
||||||
|
name: row.strategy_name,
|
||||||
|
constraints: row.constraints || [],
|
||||||
|
parameters: mapValues(row.parameters || {}, ensureStringValue),
|
||||||
|
sortOrder: row.sort_order,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
strategy.variants = row.strategy_variants || [];
|
strategy.variants = row.strategy_variants || [];
|
||||||
return strategy;
|
return strategy;
|
||||||
};
|
};
|
||||||
|
@ -64,7 +64,12 @@ export const createFeatureToggleService = (
|
|||||||
getLogger,
|
getLogger,
|
||||||
flagResolver,
|
flagResolver,
|
||||||
);
|
);
|
||||||
const featureToggleStore = new FeatureToggleStore(db, eventBus, getLogger);
|
const featureToggleStore = new FeatureToggleStore(
|
||||||
|
db,
|
||||||
|
eventBus,
|
||||||
|
getLogger,
|
||||||
|
flagResolver,
|
||||||
|
);
|
||||||
const featureToggleClientStore = new FeatureToggleClientStore(
|
const featureToggleClientStore = new FeatureToggleClientStore(
|
||||||
db,
|
db,
|
||||||
eventBus,
|
eventBus,
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import sortBy from 'lodash.sortby';
|
||||||
|
|
||||||
interface Difference {
|
interface Difference {
|
||||||
index: (string | number)[];
|
index: (string | number)[];
|
||||||
reason: string;
|
reason: string;
|
||||||
@ -18,8 +20,11 @@ export function deepDiff(arr1: any[], arr2: any[]): Difference[] | null {
|
|||||||
valueB: b,
|
valueB: b,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
for (let i = 0; i < a.length; i++) {
|
const sortedA = sortBy(a, 'name');
|
||||||
compare(a[i], b[i], parentIndex.concat(i));
|
const sortedB = sortBy(b, 'name');
|
||||||
|
|
||||||
|
for (let i = 0; i < sortedA.length; i++) {
|
||||||
|
compare(sortedA[i], sortedB[i], parentIndex.concat(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
@ -31,7 +36,10 @@ export function deepDiff(arr1: any[], arr2: any[]): Difference[] | null {
|
|||||||
const keysA = Object.keys(a);
|
const keysA = Object.keys(a);
|
||||||
const keysB = Object.keys(b);
|
const keysB = Object.keys(b);
|
||||||
|
|
||||||
if (!arraysEqual(keysA, keysB)) {
|
if (
|
||||||
|
keysA.length !== keysB.length ||
|
||||||
|
!keysA.every((key) => keysB.includes(key))
|
||||||
|
) {
|
||||||
diff.push({
|
diff.push({
|
||||||
index: parentIndex,
|
index: parentIndex,
|
||||||
reason: 'Different keys',
|
reason: 'Different keys',
|
||||||
@ -53,13 +61,6 @@ export function deepDiff(arr1: any[], arr2: any[]): Difference[] | null {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function arraysEqual(a: any[], b: any[]): boolean {
|
|
||||||
return (
|
|
||||||
a.length === b.length &&
|
|
||||||
a.sort().every((val, index) => val === b.sort()[index])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
compare(arr1, arr2, []);
|
compare(arr1, arr2, []);
|
||||||
|
|
||||||
return diff.length > 0 ? diff : null;
|
return diff.length > 0 ? diff : null;
|
||||||
|
@ -64,10 +64,19 @@ export default class FeatureToggleStore implements IFeatureToggleStore {
|
|||||||
|
|
||||||
private featureToggleRowConverter: FeatureToggleRowConverter;
|
private featureToggleRowConverter: FeatureToggleRowConverter;
|
||||||
|
|
||||||
constructor(db: Db, eventBus: EventEmitter, getLogger: LogProvider) {
|
private flagResolver: IFlagResolver;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
db: Db,
|
||||||
|
eventBus: EventEmitter,
|
||||||
|
getLogger: LogProvider,
|
||||||
|
flagResolver: IFlagResolver,
|
||||||
|
) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.logger = getLogger('feature-toggle-store.ts');
|
this.logger = getLogger('feature-toggle-store.ts');
|
||||||
this.featureToggleRowConverter = new FeatureToggleRowConverter();
|
this.featureToggleRowConverter = new FeatureToggleRowConverter(
|
||||||
|
flagResolver,
|
||||||
|
);
|
||||||
this.timer = (action) =>
|
this.timer = (action) =>
|
||||||
metricsHelper.wrapTimer(eventBus, DB_TIME, {
|
metricsHelper.wrapTimer(eventBus, DB_TIME, {
|
||||||
store: 'feature-toggle',
|
store: 'feature-toggle',
|
||||||
|
@ -1,6 +1,24 @@
|
|||||||
import { deepDiff } from '../deep-diff'; // Import the deepDiff function
|
import { deepDiff } from '../deep-diff'; // Import the deepDiff function
|
||||||
|
|
||||||
describe('deepDiff', () => {
|
describe('deepDiff', () => {
|
||||||
|
test('should sort arrays by name before comparing', () => {
|
||||||
|
// Define two arrays that are identical except for the order of elements
|
||||||
|
const array1 = [
|
||||||
|
{ name: 'b', value: 2 },
|
||||||
|
{ name: 'a', value: 1 },
|
||||||
|
];
|
||||||
|
const array2 = [
|
||||||
|
{ name: 'a', value: 1 },
|
||||||
|
{ name: 'b', value: 2 },
|
||||||
|
];
|
||||||
|
|
||||||
|
// If the function correctly sorts before comparing, there should be no differences
|
||||||
|
const result = deepDiff(array1, array2);
|
||||||
|
|
||||||
|
// Assert that there is no difference
|
||||||
|
expect(result).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
it('should return null for equal arrays', () => {
|
it('should return null for equal arrays', () => {
|
||||||
const arr1 = [1, 2, 3];
|
const arr1 = [1, 2, 3];
|
||||||
const arr2 = [1, 2, 3];
|
const arr2 = [1, 2, 3];
|
||||||
|
@ -57,7 +57,12 @@ export const createProjectService = (
|
|||||||
flagResolver,
|
flagResolver,
|
||||||
);
|
);
|
||||||
const groupStore = new GroupStore(db);
|
const groupStore = new GroupStore(db);
|
||||||
const featureToggleStore = new FeatureToggleStore(db, eventBus, getLogger);
|
const featureToggleStore = new FeatureToggleStore(
|
||||||
|
db,
|
||||||
|
eventBus,
|
||||||
|
getLogger,
|
||||||
|
flagResolver,
|
||||||
|
);
|
||||||
const featureTypeStore = new FeatureTypeStore(db, getLogger);
|
const featureTypeStore = new FeatureTypeStore(db, getLogger);
|
||||||
const accountStore = new AccountStore(db, getLogger);
|
const accountStore = new AccountStore(db, getLogger);
|
||||||
const environmentStore = new EnvironmentStore(db, eventBus, getLogger);
|
const environmentStore = new EnvironmentStore(db, eventBus, getLogger);
|
||||||
|
@ -19,6 +19,7 @@ export const createLastSeenService = (
|
|||||||
db,
|
db,
|
||||||
config.eventBus,
|
config.eventBus,
|
||||||
config.getLogger,
|
config.getLogger,
|
||||||
|
config.flagResolver,
|
||||||
);
|
);
|
||||||
|
|
||||||
return new LastSeenService({ lastSeenStore, featureToggleStore }, config);
|
return new LastSeenService({ lastSeenStore, featureToggleStore }, config);
|
||||||
|
Loading…
Reference in New Issue
Block a user