Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 7 additions & 14 deletions lib/project_config/project_config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { find, objectEntries, objectValues, keyBy } from '../utils/fns';
import { find, objectEntries, objectValues, keyBy, assignBy } from '../utils/fns';

import { FEATURE_VARIABLE_TYPES } from '../utils/enums';
import configValidator from '../utils/config_validator';
Expand Down Expand Up @@ -180,10 +180,10 @@ export const createProjectConfig = function(datafileObj?: JSON, datafileStr: str
audience.conditions = JSON.parse(audience.conditions as string);
});

projectConfig.audiencesById = {
...keyBy(projectConfig.audiences, 'id'),
...keyBy(projectConfig.typedAudiences, 'id'),
}

projectConfig.audiencesById = {};
assignBy(projectConfig.audiences, 'id', projectConfig.audiencesById);
assignBy(projectConfig.typedAudiences, 'id', projectConfig.audiencesById);

projectConfig.attributes = projectConfig.attributes || [];
projectConfig.attributeKeyMap = {};
Expand Down Expand Up @@ -267,11 +267,7 @@ export const createProjectConfig = function(datafileObj?: JSON, datafileStr: str
// Creates { <variationKey>: <variation> } map inside of the experiment
experiment.variationKeyMap = keyBy(experiment.variations, 'key');

// Creates { <variationId>: { key: <variationKey>, id: <variationId> } } mapping for quick lookup
projectConfig.variationIdMap = {
...projectConfig.variationIdMap,
...keyBy(experiment.variations, 'id')
};
assignBy(experiment.variations, 'id', projectConfig.variationIdMap);

objectValues(experiment.variationKeyMap || {}).forEach(variation => {
if (variation.variables) {
Expand Down Expand Up @@ -373,10 +369,7 @@ const parseHoldoutsConfig = (projectConfig: ProjectConfig): void => {

holdout.variationKeyMap = keyBy(holdout.variations, 'key');

projectConfig.variationIdMap = {
...projectConfig.variationIdMap,
...keyBy(holdout.variations, 'id'),
};
assignBy(holdout.variations, 'id', projectConfig.variationIdMap);

if (holdout.includedFlags.length === 0) {
projectConfig.globalHoldouts.push(holdout);
Expand Down
76 changes: 74 additions & 2 deletions lib/utils/fns/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, it, expect } from 'vitest';

import { groupBy, objectEntries, objectValues, find, keyByUtil, sprintf } from '.'
import { groupBy, objectEntries, objectValues, find, sprintf, keyBy, assignBy } from '.'

describe('utils', () => {
describe('groupBy', () => {
Expand Down Expand Up @@ -68,14 +68,86 @@ describe('utils', () => {
{ key: 'baz', firstName: 'james', lastName: 'foxy' },
]

expect(keyByUtil(input, item => item.key)).toEqual({
expect(keyBy(input, 'key')).toEqual({
foo: { key: 'foo', firstName: 'jordan', lastName: 'foo' },
bar: { key: 'bar', firstName: 'jordan', lastName: 'bar' },
baz: { key: 'baz', firstName: 'james', lastName: 'foxy' },
})
})
})

describe('assignBy', () => {
it('should assign array elements to an object using the specified key', () => {
const input = [
{ key: 'foo', firstName: 'jordan', lastName: 'foo' },
{ key: 'bar', firstName: 'jordan', lastName: 'bar' },
{ key: 'baz', firstName: 'james', lastName: 'foxy' },
]
const base = {}

assignBy(input, 'key', base)

expect(base).toEqual({
foo: { key: 'foo', firstName: 'jordan', lastName: 'foo' },
bar: { key: 'bar', firstName: 'jordan', lastName: 'bar' },
baz: { key: 'baz', firstName: 'james', lastName: 'foxy' },
})
})

it('should append to an existing object', () => {
const input = [
{ key: 'foo', firstName: 'jordan', lastName: 'foo' },
{ key: 'bar', firstName: 'jordan', lastName: 'bar' },
]
const base: any = { existing: 'value' }

assignBy(input, 'key', base)

expect(base).toEqual({
existing: 'value',
foo: { key: 'foo', firstName: 'jordan', lastName: 'foo' },
bar: { key: 'bar', firstName: 'jordan', lastName: 'bar' },
})
})

it('should handle empty array', () => {
const base: any = { existing: 'value' }

assignBy([], 'key', base)

expect(base).toEqual({ existing: 'value' })
})

it('should handle null/undefined array', () => {
const base: any = { existing: 'value' }

assignBy(null as any, 'key', base)
expect(base).toEqual({ existing: 'value' })

assignBy(undefined as any, 'key', base)
expect(base).toEqual({ existing: 'value' })
})

it('should override existing values with the same key', () => {
const input = [
{ key: 'foo', firstName: 'jordan', lastName: 'updated' },
{ key: 'bar', firstName: 'james', lastName: 'new' },
]
const base: any = {
foo: { key: 'foo', firstName: 'john', lastName: 'original' },
existing: 'value'
}

assignBy(input, 'key', base)

expect(base).toEqual({
existing: 'value',
foo: { key: 'foo', firstName: 'jordan', lastName: 'updated' },
bar: { key: 'bar', firstName: 'james', lastName: 'new' },
})
})
})

describe('sprintf', () => {
it('sprintf(msg)', () => {
expect(sprintf('this is my message')).toBe('this is my message')
Expand Down
26 changes: 12 additions & 14 deletions lib/utils/fns/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,19 @@ export function isSafeInteger(number: unknown): boolean {
return typeof number == 'number' && Math.abs(number) <= MAX_SAFE_INTEGER_LIMIT;
}

export function keyBy<K>(arr: K[], key: string): { [key: string]: K } {
export function keyBy<K>(arr: K[], key: string): Record<string, K> {
if (!arr) return {};
return keyByUtil(arr, function(item) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (item as any)[key];

const base: Record<string, K> = {};
assignBy(arr, key, base);
return base;
}

export function assignBy<K>(arr: K[], key: string, base: Record<string, K>): void {
if (!arr) return;

arr.forEach((e) => {
base[(e as any)[key]] = e;
});
}

Expand Down Expand Up @@ -81,15 +89,6 @@ export function find<K>(arr: K[], cond: (arg: K) => boolean): K | undefined {
return found;
}

export function keyByUtil<K>(arr: K[], keyByFn: (item: K) => string): { [key: string]: K } {
const map: { [key: string]: K } = {};
arr.forEach(item => {
const key = keyByFn(item);
map[key] = item;
});
return map;
}

// TODO[OASIS-6649]: Don't use any type
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function sprintf(format: string, ...args: any[]): string {
Expand Down Expand Up @@ -129,6 +128,5 @@ export default {
objectValues,
objectEntries,
find,
keyByUtil,
sprintf,
};
Loading