Skip to content

Commit 1e0a86b

Browse files
[FSSDK-10766] decide & decideForKeys adjustment
1 parent 5a413d3 commit 1e0a86b

File tree

2 files changed

+111
-99
lines changed

2 files changed

+111
-99
lines changed

lib/optimizely/index.ts

Lines changed: 110 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1490,105 +1490,16 @@ export default class Optimizely implements Client {
14901490
}
14911491

14921492
decide(user: OptimizelyUserContext, key: string, options: OptimizelyDecideOption[] = []): OptimizelyDecision {
1493-
const userId = user.getUserId();
1494-
const attributes = user.getAttributes();
14951493
const configObj = this.projectConfigManager.getConfig();
1496-
const reasons: (string | number)[][] = [];
1497-
let decisionObj: DecisionObj;
1494+
14981495
if (!this.isValidInstance() || !configObj) {
14991496
this.logger.log(LOG_LEVEL.INFO, LOG_MESSAGES.INVALID_OBJECT, MODULE_NAME, 'decide');
15001497
return newErrorDecision(key, user, [DECISION_MESSAGES.SDK_NOT_READY]);
15011498
}
15021499

1503-
const feature = configObj.featureKeyMap[key];
1504-
if (!feature) {
1505-
this.logger.log(LOG_LEVEL.ERROR, ERROR_MESSAGES.FEATURE_NOT_IN_DATAFILE, MODULE_NAME, key);
1506-
return newErrorDecision(key, user, [sprintf(DECISION_MESSAGES.FLAG_KEY_INVALID, key)]);
1507-
}
1508-
1509-
const allDecideOptions = this.getAllDecideOptions(options);
1510-
1511-
const forcedDecisionResponse = this.decisionService.findValidatedForcedDecision(configObj, user, key);
1512-
reasons.push(...forcedDecisionResponse.reasons);
1513-
const variation = forcedDecisionResponse.result;
1514-
if (variation) {
1515-
decisionObj = {
1516-
experiment: null,
1517-
variation: variation,
1518-
decisionSource: DECISION_SOURCES.FEATURE_TEST,
1519-
};
1520-
} else {
1521-
const decisionVariation = this.decisionService.getVariationForFeature(configObj, feature, user, allDecideOptions);
1522-
reasons.push(...decisionVariation.reasons);
1523-
decisionObj = decisionVariation.result;
1524-
}
1525-
const decisionSource = decisionObj.decisionSource;
1526-
const experimentKey = decisionObj.experiment?.key ?? null;
1527-
const variationKey = decisionObj.variation?.key ?? null;
1528-
const flagEnabled: boolean = decision.getFeatureEnabledFromVariation(decisionObj);
1529-
if (flagEnabled === true) {
1530-
this.logger.log(LOG_LEVEL.INFO, LOG_MESSAGES.FEATURE_ENABLED_FOR_USER, MODULE_NAME, key, userId);
1531-
} else {
1532-
this.logger.log(LOG_LEVEL.INFO, LOG_MESSAGES.FEATURE_NOT_ENABLED_FOR_USER, MODULE_NAME, key, userId);
1533-
}
1534-
1535-
const variablesMap: { [key: string]: unknown } = {};
1536-
let decisionEventDispatched = false;
1537-
1538-
if (!allDecideOptions[OptimizelyDecideOption.EXCLUDE_VARIABLES]) {
1539-
feature.variables.forEach(variable => {
1540-
variablesMap[variable.key] = this.getFeatureVariableValueFromVariation(
1541-
key,
1542-
flagEnabled,
1543-
decisionObj.variation,
1544-
variable,
1545-
userId
1546-
);
1547-
});
1548-
}
1500+
options.filter(option => option !== OptimizelyDecideOption.ENABLED_FLAGS_ONLY);
15491501

1550-
if (
1551-
!allDecideOptions[OptimizelyDecideOption.DISABLE_DECISION_EVENT] &&
1552-
(decisionSource === DECISION_SOURCES.FEATURE_TEST ||
1553-
(decisionSource === DECISION_SOURCES.ROLLOUT && projectConfig.getSendFlagDecisionsValue(configObj)))
1554-
) {
1555-
this.sendImpressionEvent(decisionObj, key, userId, flagEnabled, attributes);
1556-
decisionEventDispatched = true;
1557-
}
1558-
1559-
const shouldIncludeReasons = allDecideOptions[OptimizelyDecideOption.INCLUDE_REASONS];
1560-
1561-
let reportedReasons: string[] = [];
1562-
if (shouldIncludeReasons) {
1563-
reportedReasons = reasons.map(reason => sprintf(reason[0] as string, ...reason.slice(1)));
1564-
}
1565-
1566-
const featureInfo = {
1567-
flagKey: key,
1568-
enabled: flagEnabled,
1569-
variationKey: variationKey,
1570-
ruleKey: experimentKey,
1571-
variables: variablesMap,
1572-
reasons: reportedReasons,
1573-
decisionEventDispatched: decisionEventDispatched,
1574-
};
1575-
1576-
this.notificationCenter.sendNotifications(NOTIFICATION_TYPES.DECISION, {
1577-
type: DECISION_NOTIFICATION_TYPES.FLAG,
1578-
userId: userId,
1579-
attributes: attributes,
1580-
decisionInfo: featureInfo,
1581-
});
1582-
1583-
return {
1584-
variationKey: variationKey,
1585-
enabled: flagEnabled,
1586-
variables: variablesMap,
1587-
ruleKey: experimentKey,
1588-
flagKey: key,
1589-
userContext: user,
1590-
reasons: reportedReasons,
1591-
};
1502+
return this.decideForKeys(user, [key], options)[key];
15921503
}
15931504

15941505
/**
@@ -1629,7 +1540,9 @@ export default class Optimizely implements Client {
16291540
options: OptimizelyDecideOption[] = []
16301541
): { [key: string]: OptimizelyDecision } {
16311542
const decisionMap: { [key: string]: OptimizelyDecision } = {};
1632-
if (!this.isValidInstance()) {
1543+
const configObj = this.projectConfigManager.getConfig()
1544+
1545+
if (!this.isValidInstance() || !configObj) {
16331546
this.logger.log(LOG_LEVEL.ERROR, LOG_MESSAGES.INVALID_OBJECT, MODULE_NAME, 'decideForKeys');
16341547
return decisionMap;
16351548
}
@@ -1638,12 +1551,111 @@ export default class Optimizely implements Client {
16381551
}
16391552

16401553
const allDecideOptions = this.getAllDecideOptions(options);
1641-
keys.forEach(key => {
1642-
const optimizelyDecision: OptimizelyDecision = this.decide(user, key, options);
1643-
if (!allDecideOptions[OptimizelyDecideOption.ENABLED_FLAGS_ONLY] || optimizelyDecision.enabled) {
1644-
decisionMap[key] = optimizelyDecision;
1554+
1555+
for(const key of keys) {
1556+
const feature = configObj.featureKeyMap[key];
1557+
if (!feature) {
1558+
this.logger.log(LOG_LEVEL.ERROR, ERROR_MESSAGES.FEATURE_NOT_IN_DATAFILE, MODULE_NAME, key);
1559+
decisionMap[key] = newErrorDecision(key, user, [sprintf(DECISION_MESSAGES.FLAG_KEY_INVALID, key)]);
1560+
continue
16451561
}
1646-
});
1562+
1563+
const userId = user.getUserId();
1564+
const attributes = user.getAttributes();
1565+
const reasons: (string | number)[][] = [];
1566+
const forcedDecisionResponse = this.decisionService.findValidatedForcedDecision(configObj, user, key);
1567+
reasons.push(...forcedDecisionResponse.reasons);
1568+
const variation = forcedDecisionResponse.result;
1569+
let decisionObj: DecisionObj;
1570+
1571+
if (variation) {
1572+
decisionObj = {
1573+
experiment: null,
1574+
variation: variation,
1575+
decisionSource: DECISION_SOURCES.FEATURE_TEST,
1576+
};
1577+
} else {
1578+
const decisionVariation = this.decisionService.getVariationForFeature(
1579+
configObj,
1580+
feature,
1581+
user,
1582+
allDecideOptions
1583+
);
1584+
reasons.push(...decisionVariation.reasons);
1585+
decisionObj = decisionVariation.result;
1586+
}
1587+
1588+
const decisionSource = decisionObj.decisionSource;
1589+
const experimentKey = decisionObj.experiment?.key ?? null;
1590+
const variationKey = decisionObj.variation?.key ?? null;
1591+
const flagEnabled: boolean = decision.getFeatureEnabledFromVariation(decisionObj);
1592+
1593+
if (flagEnabled) {
1594+
this.logger.log(LOG_LEVEL.INFO, LOG_MESSAGES.FEATURE_ENABLED_FOR_USER, MODULE_NAME, key, userId);
1595+
} else {
1596+
this.logger.log(LOG_LEVEL.INFO, LOG_MESSAGES.FEATURE_NOT_ENABLED_FOR_USER, MODULE_NAME, key, userId);
1597+
}
1598+
1599+
const variablesMap: { [key: string]: unknown } = {};
1600+
let decisionEventDispatched = false;
1601+
1602+
if (!allDecideOptions[OptimizelyDecideOption.EXCLUDE_VARIABLES]) {
1603+
feature.variables.forEach(variable => {
1604+
variablesMap[variable.key] = this.getFeatureVariableValueFromVariation(
1605+
key,
1606+
flagEnabled,
1607+
decisionObj.variation,
1608+
variable,
1609+
userId
1610+
);
1611+
});
1612+
}
1613+
1614+
if (
1615+
!allDecideOptions[OptimizelyDecideOption.DISABLE_DECISION_EVENT] &&
1616+
(decisionSource === DECISION_SOURCES.FEATURE_TEST ||
1617+
(decisionSource === DECISION_SOURCES.ROLLOUT && projectConfig.getSendFlagDecisionsValue(configObj)))
1618+
) {
1619+
this.sendImpressionEvent(decisionObj, key, userId, flagEnabled, attributes);
1620+
decisionEventDispatched = true;
1621+
}
1622+
1623+
const shouldIncludeReasons = allDecideOptions[OptimizelyDecideOption.INCLUDE_REASONS];
1624+
1625+
let reportedReasons: string[] = [];
1626+
if (shouldIncludeReasons) {
1627+
reportedReasons = reasons.map(reason => sprintf(reason[0] as string, ...reason.slice(1)));
1628+
}
1629+
1630+
const featureInfo = {
1631+
flagKey: key,
1632+
enabled: flagEnabled,
1633+
variationKey: variationKey,
1634+
ruleKey: experimentKey,
1635+
variables: variablesMap,
1636+
reasons: reportedReasons,
1637+
decisionEventDispatched: decisionEventDispatched,
1638+
};
1639+
1640+
this.notificationCenter.sendNotifications(NOTIFICATION_TYPES.DECISION, {
1641+
type: DECISION_NOTIFICATION_TYPES.FLAG,
1642+
userId: userId,
1643+
attributes: attributes,
1644+
decisionInfo: featureInfo,
1645+
});
1646+
1647+
if (!allDecideOptions[OptimizelyDecideOption.ENABLED_FLAGS_ONLY] || flagEnabled) {
1648+
decisionMap[key] = {
1649+
variationKey: variationKey,
1650+
enabled: flagEnabled,
1651+
variables: variablesMap,
1652+
ruleKey: experimentKey,
1653+
flagKey: key,
1654+
userContext: user,
1655+
reasons: reportedReasons,
1656+
};
1657+
}
1658+
}
16471659

16481660
return decisionMap;
16491661
}

lib/optimizely_user_context/index.tests.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ describe('lib/optimizely_user_context', function() {
3535
describe('APIs', function() {
3636
var fakeOptimizely;
3737
var userId = 'tester';
38-
var options = 'fakeOption';
38+
var options = ['fakeOption'];
3939
describe('#setAttribute', function() {
4040
fakeOptimizely = {
4141
decide: sinon.stub().returns({}),

0 commit comments

Comments
 (0)