Skip to content
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

feat(flag-decisions): Add support for sending flag decisions along with decision metadata. #370

Merged
merged 15 commits into from
Oct 20, 2020
48 changes: 32 additions & 16 deletions Sources/Data Model/DispatchEvents/BatchEvent.swift
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
/****************************************************************************
* Copyright 2019, Optimizely, Inc. and contributors *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
***************************************************************************/
* Copyright 2019-2020, Optimizely, Inc. and contributors *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
***************************************************************************/

import Foundation

Expand Down Expand Up @@ -79,15 +79,31 @@ struct Snapshot: Codable, Equatable {
let events: [DispatchEvent]
}

struct DecisionMetadata: Codable, Equatable {
let ruleType: String
let ruleKey: String
let flagKey: String
let variationKey: String

enum CodingKeys: String, CodingKey {
case ruleType = "rule_type"
case ruleKey = "rule_key"
case flagKey = "flag_key"
case variationKey = "variation_key"
}
}

struct Decision: Codable, Equatable {
let variationID: String
let campaignID: String
let experimentID: String
let metaData: DecisionMetadata

enum CodingKeys: String, CodingKey {
case variationID = "variation_id"
case campaignID = "campaign_id"
case experimentID = "experiment_id"
case metaData = "metadata"
}
}

Expand All @@ -104,7 +120,7 @@ struct DispatchEvent: Codable, Equatable {
var tags: [String: AttributeValue]?
var revenue: AttributeValue?
var value: AttributeValue?

Copy link
Contributor

Choose a reason for hiding this comment

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

remove these extra spaces.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this spacing is being added automatically by the new xcode, it follows the same spacing as the previous line.

enum CodingKeys: String, CodingKey {
case entityID = "entity_id"
case key
Expand All @@ -124,7 +140,7 @@ struct DispatchEvent: Codable, Equatable {
revenue: AttributeValue? = nil) {

// TODO: add validation and throw here for invalid value (int, double) and revenue (int) types

Copy link
Contributor

Choose a reason for hiding this comment

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

remove these extra spaces.

self.timestamp = timestamp
self.key = key
self.entityID = entityID
Expand Down
37 changes: 19 additions & 18 deletions Sources/Data Model/Project.swift
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
/****************************************************************************
* Copyright 2019-2020, Optimizely, Inc. and contributors *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
***************************************************************************/
* Copyright 2019-2020, Optimizely, Inc. and contributors *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
***************************************************************************/

import Foundation

Expand Down Expand Up @@ -42,23 +42,24 @@ struct Project: Codable, Equatable {
var typedAudiences: [Audience]?
var featureFlags: [FeatureFlag]
var botFiltering: Bool?
var sendFlagDecisions: Bool?
Copy link
Contributor

Choose a reason for hiding this comment

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

It's not nullable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since Project struct is marked codable, for every value that might not exist, we have to mark it as optional, otherwise decoding a datafile with no sendFlagDecisions into Project struct will cause a crash.


let logger = OPTLoggerFactory.getLogger()

// Required since logger in not decodable
// Required since logger is not decodable
enum CodingKeys: String, CodingKey {
// V2
case version, projectId, experiments, audiences, groups, attributes, accountId, events, revision
// V3
case anonymizeIP
// V4
case rollouts, typedAudiences, featureFlags, botFiltering
case rollouts, typedAudiences, featureFlags, botFiltering, sendFlagDecisions
}

// Required since logger in not equatable
// Required since logger is not equatable
static func ==(lhs: Project, rhs: Project) -> Bool {
return lhs.version == rhs.version && lhs.projectId == rhs.projectId && lhs.experiments == rhs.experiments &&
lhs.audiences == rhs.audiences && lhs.groups == rhs.groups && lhs.attributes == rhs.attributes && lhs.accountId == rhs.accountId && lhs.events == rhs.events && lhs.revision == rhs.revision && lhs.anonymizeIP == rhs.anonymizeIP && lhs.rollouts == rhs.rollouts && lhs.typedAudiences == rhs.typedAudiences && lhs.featureFlags == rhs.featureFlags && lhs.botFiltering == rhs.botFiltering
lhs.audiences == rhs.audiences && lhs.groups == rhs.groups && lhs.attributes == rhs.attributes && lhs.accountId == rhs.accountId && lhs.events == rhs.events && lhs.revision == rhs.revision && lhs.anonymizeIP == rhs.anonymizeIP && lhs.rollouts == rhs.rollouts && lhs.typedAudiences == rhs.typedAudiences && lhs.featureFlags == rhs.featureFlags && lhs.botFiltering == rhs.botFiltering && lhs.sendFlagDecisions == rhs.sendFlagDecisions
}
}

Expand Down
53 changes: 30 additions & 23 deletions Sources/Data Model/ProjectConfig.swift
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
/****************************************************************************
* Copyright 2019, Optimizely, Inc. and contributors *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
***************************************************************************/
* Copyright 2019-2020, Optimizely, Inc. and contributors *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
***************************************************************************/

import Foundation

Expand All @@ -34,13 +34,13 @@ class ProjectConfig {
}
return map
}()

Copy link
Contributor

Choose a reason for hiding this comment

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

remove all empty spaces across all files.

lazy var experimentIdMap: [String: Experiment] = {
var map = [String: Experiment]()
allExperiments.forEach { map[$0.id] = $0 }
return map
}()

lazy var experimentFeatureMap: [String: [String]] = {
var experimentFeatureMap = [String: [String]]()
project.featureFlags.forEach { (ff) in
Expand All @@ -67,25 +67,25 @@ class ProjectConfig {
project.attributes.forEach { map[$0.key] = $0 }
return map
}()

lazy var featureFlagKeyMap: [String: FeatureFlag] = {
var map = [String: FeatureFlag]()
project.featureFlags.forEach { map[$0.key] = $0 }
return map
}()

lazy var rolloutIdMap: [String: Rollout] = {
var map = [String: Rollout]()
project.rollouts.forEach { map[$0.id] = $0 }
return map
}()

lazy var allExperiments: [Experiment] = {
return project.experiments + project.groups.map { $0.experiments }.flatMap({$0})
}()

// MARK: - Init

init(datafile: Data) throws {
do {
self.project = try JSONDecoder().decode(Project.self, from: datafile)
Expand Down Expand Up @@ -142,7 +142,7 @@ extension ProjectConfig {
}

static var observer = ProjectObserver()

}

// MARK: - Persistent Data
Expand Down Expand Up @@ -177,6 +177,13 @@ extension ProjectConfig {

extension ProjectConfig {

/**
* Get sendFlagDecisions value.
*/
var sendFlagDecisions: Bool {
return project.sendFlagDecisions ?? false
}

/**
* Get an Experiment object for a key.
*/
Expand Down Expand Up @@ -306,12 +313,12 @@ extension ProjectConfig {

// TODO: common function to trim all keys
variationKey = variationKey.trimmingCharacters(in: NSCharacterSet.whitespaces)

guard !variationKey.isEmpty else {
logger.e(.variationKeyInvalid(experimentKey, variationKey))
return false
}

guard let variation = experiment.getVariation(key: variationKey) else {
logger.e(.variationKeyInvalid(experimentKey, variationKey))
return false
Expand Down
Loading