8000 feat: datafile accessor by pthompson127 · Pull Request #535 · optimizely/javascript-sdk · GitHub
[go: up one dir, main page]

Skip to content

feat: datafile accessor #535

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 28 commits into from
Sep 9, 2020
Merged

feat: datafile accessor #535

merged 28 commits into from
Sep 9, 2020

Conversation

pthompson127
Copy link
Contributor
@pthompson127 pthompson127 commented Jul 24, 2020

Summary

Add a getDatafile method to the OptimizelyConfig object, that returns a string version of the datafile currently being used by the instance.

  • toDatafile function added in project_config module to encapsulate conversion of project config to datafile string
  • Parsing & validation code updated (in both optimizely-sdk and updated datafile-manager version) to only call JSON.parse at most once.

Test Plan

  • Manual testing
  • Passing new FSC datafile accessor tests
  • Updated unit tests

@pthompson127 pthompson127 requested a review from a team as a code owner July 24, 2020 23:13
@pthompson127 pthompson127 requested a review from mjc1283 July 24, 2020 23:13
@pthompson127 pthompson127 marked this pull request as draft July 24, 2020 23:13
Copy link
Contributor
@mjc1283 mjc1283 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pthompson127 I'll DM you to discuss further - I think we could try to make this more similar to the approach in Python SDK, rather than keeping track of the datafile string within project config manager.

Comment on lines 24 to 25
this.experimentsMap = this.__getExperimentsMap(configObj);
this.featuresMap = this.__getFeaturesMap(configObj, this.experimentsMap);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getExperimentsMap, getFeaturesMap, getMergedVariablesMap, etc. don't need to become methods of OptimizelyConfig. We could leave them as free functions, then these two lines could be:

Suggested change
this.experimentsMap = this.__getExperimentsMap(configObj);
this.featuresMap = this.__getFeaturesMap(configObj, this.experimentsMap);
this.experimentsMap = getExperimentsMap(configObj);
this.featuresMap = getFeaturesMap(configObj, this.experimentsMap);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done ✔️

@@ -20,7 +20,7 @@ import { HttpPollingDatafileManager } from '@optimizely/js-sdk-datafile-manager'
import fns from '../../utils/fns';
import { ERROR_MESSAGES } from '../../utils/enums';
import projectConfig from '../../core/project_config';
import { getOptimizelyConfig } from '../optimizely_config';
import optimizelyConfig from '../optimizely_config';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest only importing what's needed:

Suggested change
import optimizelyConfig from '../optimizely_config';
import { OptimizelyConfig } from '../optimizely_config';

then, use OptimizelyConfig directly on line 258.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done ✔️

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@msohailhussain Please try this.

if (initialDatafile && this.__configObj) {
datafileManagerConfig.datafile = initialDatafile;
if (this.__datafileObj && this.__configObj) {
datafileManagerConfig.datafile = this.__datafileObj;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should pass the string version of the datafile here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done ✔️

Comment on lines 282 to 289
/**
* Returns the datafile string
* @return {string}
*/
ProjectConfigManager.prototype.toDatafile = function() {
return this.__datafileStr;
};

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we want toDatafile on project config manager.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done ✔️

@pthompson127 pthompson127 requested a review from mjc1283 July 28, 2020 18:56
Copy link
Contributor
@mjc1283 mjc1283 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall! Mostly requesting minor changes.

There is one substantial issue: datafile-manager and optimizely-sdk are separate packages, and optimizely-sdk depends on a published version of datafile-manager. So we can't make changes in optimizely-sdk depending on the code in datafile-manager at the same commit. We have to release a new datafile-manager version and update the dependency version in order to bring new functionality in. In order to solve this, we can merge & release the datafile-manager changes first before the optimizely-sdk changes.

Comment on lines 67 to 68
projectConfig.__datafileStr = JSON.stringify(datafile);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found an issue with this code that I suggested. When we already have a string because user passed in string, we will be parsing it and then re-stringify-ing it here. To avoid this unneccessary stringify, let's do this:

export function createProjectConfig(datafileObj, datafileStr=null) {
  // ...
  projectConfig.__datafileStr = datfileStr === null ? JSON.stringify(datafileObj) : datafileStr;
  // ...
}

Then, below in tryCreatingProjectConfig:

// ...
var createArgs = [newDatafileObj];
if (typeof config.datafile === 'string') {
  // We know config.datafile is a valid JSON datafile string because it was validated above
  createArgs.push(config.datafile)
}
var newConfigObj = this.createProjectConfig(...createArgs);
// ...

@@ -539,24 +542,54 @@ export var isFeatureExperiment = function(projectConfig, experimentId) {
return projectConfig.experimentFeatureMap.hasOwnProperty(experimentId);
};

/**
*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a short description of what toDatafile returns.

67E6
this.__datafile = datafile;
}

OptimizelyConfig.prototype.getDatafile = function() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a JSDoc comment with the return type.

@@ -15,16 +15,6 @@
*/
import { isFeatureExperiment } from '../project_config';

// Get Experiment Ids which are part of rollouts
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there's any material difference in getRolloutExperimentIds or getFeaturesMap, rather they appear in this diff because they were reordered within the file. Could you restore them to the original order just to confirm that?

A3E2
Comment on lines +14 to +16
// Note: The TS compiler determines what syntax is accepted. We're using TS version 3.3.3333.
// This seems to roughly correspond to "2018" for this setting.
ecmaVersion: 2018,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops...I thought your branch was based on https://github.com/optimizely/javascript-sdk/tree/mcarroll/optimizely-sdk-typescript, so I suggested adding some newer syntax. But I see now this PR is against master. I suppose the easiest thing now is to wait until we can merge https://github.com/optimizely/javascript-sdk/tree/mcarroll/optimizely-sdk-typescript into master before merging these changes.

We can address this later, as the first step for this PR should be separating out and pushing through the datafile manager changes.

@coveralls
Copy link
coveralls commented Aug 8, 2020

Coverage Status

Coverage decreased (-0.007%) to 96.733% when pulling 87a1746 on peter/getDatafile into 80b4108 on master.

@pthompson127 pthompson127 marked this pull request as ready for review August 19, 2020 17:38
@pthompson127 pthompson127 changed the title feat: datafile accessor (WIP) feat: datafile accessor Aug 21, 2020
@msohailhussain
Copy link
Contributor

@msohailhussain msohailhussain changed the title feat: datafile accessor - WIP feat: datafile accessor Sep 3, 2020
@msohailhussain msohailhussain removed their assignment Sep 3, 2020
@@ -739,31 +739,29 @@ describe('lib/core/project_config', function() {
jsonSchemaValidator: stubJsonSchemaValidator,
logger: logger,
});
assert.deepEqual(result, configObj);
assert.deepEqual(result.configObj, configObj);
});

it('throws an error when validateDatafile throws', function() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
it('throws an error when validateDatafile throws', function() {
it('returns an error when validateDatafile throws', function() {

});
assert.isNotNull(error);
});

it('throws an error when jsonSchemaValidator.validate throws', function() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
it('throws an error when jsonSchemaValidator.validate throws', function() {
it('returns an error when jsonSchemaValidator.validate throws', function() {

}
return this.createProjectConfig(config.datafile);
var newConfigObj = this.createProjectConfig(...createProjectConfigArgs);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this used here? We are not in a method of an object, this is a stand-alone function. I suggest the following change:

Suggested change
var newConfigObj = this.createProjectConfig(...createProjectConfigArgs);
var newConfigObj = createProjectConfig(...createProjectConfigArgs);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was causing to call real function instead of stubbed function, that's why this is mandatory here.

@@ -20,7 +20,7 @@ import { HttpPollingDatafileManager } from '@optimizely/js-sdk-datafile-manager'
import fns from '../../utils/fns';
import { ERROR_MESSAGES } from '../../utils/enums';
import projectConfig from '../../core/project_config';
import { getOptimizelyConfig } from '../optimizely_config';
import optimizelyConfig from '../optimizely_config';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@msohailhussain Please try this.

@@ -118,8 +103,8 @@ ProjectConfigManager.prototype.__initialize = function(config) {
if (this.__validateDatafileOptions(config.datafileOptions)) {
assign(datafileManagerConfig, config.datafileOptions);
}
if (initialDatafile && this.__configObj) {
datafileManagerConfig.datafile = initialDatafile;
if (!handleNewDatafileException) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer checking this.__configObj here, even though handleNewDatafileException can be used as an indirect signal, we should be direct. An error will be thrown if toDatafile is passed null.

Suggested change
if (!handleNewDatafileException) {
if (this.__configObj) {

@@ -23,7 +23,7 @@ import * as datafileManager from '@optimizely/js-sdk-datafile-manager';
import projectConfig from './index';
import { ERROR_MESSAGES, LOG_MESSAGES } from '../../utils/enums';
import testData from '../../tests/test_data';
import * as optimizelyConfig from '../optimizely_config/index';
import optimizelyConfig from '../optimizely_config/index';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change? For multi-value modules, I prefer using named imports or the namespace import style as much as possible.

Comment on lines 144 to 146
sinon.assert.calledOnce(stubLogHandler.log);
var logMessage = stubLogHandler.log.args[0][1];
assert.strictEqual(logMessage, sprintf(LOG_MESSAGES.VALID_DATAFILE, 'PROJECT_CONFIG'));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This message should still be logged, is it not?

@@ -130,4 +130,6 @@ OptimizelyConfig.prototype.getDatafile = function() {
return this.__datafile;
}

export default OptimizelyConfig
export default {
OptimizelyConfig: OptimizelyConfig
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unable to stub, that's why passing object.

@mjc1283 mjc1283 merged commit 03b573e into master Sep 9, 2020
@mjc1283 mjc1283 deleted the peter/getDatafile branch September 9, 2020 17:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants
0