1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-22 19:07:54 +01: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:
Fredrik Strand Oseberg 2023-10-18 16:34:42 +02:00 committed by GitHub
parent 1f8d12bcdc
commit cd864ed09e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 90 additions and 24 deletions

View File

@ -123,6 +123,8 @@
"knex": "^2.4.2",
"lodash.get": "^4.4.2",
"lodash.groupby": "^4.6.0",
"lodash.isequal": "^4.5.0",
"lodash.sortby": "^4.7.0",
"log4js": "^6.0.0",
"make-fetch-happen": "^11.0.0",
"memoizee": "^0.4.15",

View File

@ -49,7 +49,12 @@ export const createStores = (
return {
eventStore,
featureToggleStore: new FeatureToggleStore(db, eventBus, getLogger),
featureToggleStore: new FeatureToggleStore(
db,
eventBus,
getLogger,
config.flagResolver,
),
featureTypeStore: new FeatureTypeStore(db, getLogger),
strategyStore: new StrategyStore(db, getLogger),
clientApplicationsStore: new ClientApplicationsStore(

View File

@ -157,6 +157,7 @@ export const deferredExportImportTogglesService = (
db,
eventBus,
getLogger,
flagResolver,
);
const tagStore = new TagStore(db, eventBus, getLogger);
const tagTypeStore = new TagTypeStore(db, eventBus, getLogger);

View File

@ -5,12 +5,19 @@ import {
FeatureToggle,
IFeatureToggleQuery,
ITag,
IFlagResolver,
} from '../../../types';
import { mapValues, ensureStringValue } from '../../../util';
import { FeatureConfigurationClient } from '../types/feature-toggle-strategies-store-type';
export class FeatureToggleRowConverter {
private flagResolver: IFlagResolver;
constructor(flagResolver: IFlagResolver) {
this.flagResolver = flagResolver;
}
isUnseenStrategyRow = (
feature: PartialDeep<IFeatureToggleClient>,
row: Record<string, any>,
@ -63,7 +70,9 @@ export class FeatureToggleRowConverter {
};
rowToStrategy = (row: Record<string, any>): IStrategyConfig => {
const strategy: IStrategyConfig = {
let strategy: IStrategyConfig;
if (this.flagResolver.isEnabled('playgroundImprovements')) {
strategy = {
id: row.strategy_id,
name: row.strategy_name,
title: row.strategy_title,
@ -72,6 +81,16 @@ export class FeatureToggleRowConverter {
sortOrder: row.sort_order,
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 || [];
return strategy;
};

View File

@ -64,7 +64,12 @@ export const createFeatureToggleService = (
getLogger,
flagResolver,
);
const featureToggleStore = new FeatureToggleStore(db, eventBus, getLogger);
const featureToggleStore = new FeatureToggleStore(
db,
eventBus,
getLogger,
flagResolver,
);
const featureToggleClientStore = new FeatureToggleClientStore(
db,
eventBus,

View File

@ -1,3 +1,5 @@
import sortBy from 'lodash.sortby';
interface Difference {
index: (string | number)[];
reason: string;
@ -18,8 +20,11 @@ export function deepDiff(arr1: any[], arr2: any[]): Difference[] | null {
valueB: b,
});
} else {
for (let i = 0; i < a.length; i++) {
compare(a[i], b[i], parentIndex.concat(i));
const sortedA = sortBy(a, 'name');
const sortedB = sortBy(b, 'name');
for (let i = 0; i < sortedA.length; i++) {
compare(sortedA[i], sortedB[i], parentIndex.concat(i));
}
}
} else if (
@ -31,7 +36,10 @@ export function deepDiff(arr1: any[], arr2: any[]): Difference[] | null {
const keysA = Object.keys(a);
const keysB = Object.keys(b);
if (!arraysEqual(keysA, keysB)) {
if (
keysA.length !== keysB.length ||
!keysA.every((key) => keysB.includes(key))
) {
diff.push({
index: parentIndex,
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, []);
return diff.length > 0 ? diff : null;

View File

@ -64,10 +64,19 @@ export default class FeatureToggleStore implements IFeatureToggleStore {
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.logger = getLogger('feature-toggle-store.ts');
this.featureToggleRowConverter = new FeatureToggleRowConverter();
this.featureToggleRowConverter = new FeatureToggleRowConverter(
flagResolver,
);
this.timer = (action) =>
metricsHelper.wrapTimer(eventBus, DB_TIME, {
store: 'feature-toggle',

View File

@ -1,6 +1,24 @@
import { deepDiff } from '../deep-diff'; // Import the deepDiff function
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', () => {
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];

View File

@ -57,7 +57,12 @@ export const createProjectService = (
flagResolver,
);
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 accountStore = new AccountStore(db, getLogger);
const environmentStore = new EnvironmentStore(db, eventBus, getLogger);

View File

@ -19,6 +19,7 @@ export const createLastSeenService = (
db,
config.eventBus,
config.getLogger,
config.flagResolver,
);
return new LastSeenService({ lastSeenStore, featureToggleStore }, config);