1 package ldmodel
2
3 import (
4 "github.com/launchdarkly/go-jsonstream/v3/jwriter"
5 "github.com/launchdarkly/go-sdk-common/v3/ldattr"
6 "github.com/launchdarkly/go-sdk-common/v3/ldcontext"
7 )
8
9
10
11
12
13
14
15
16
17
18
19
20
21 func marshalFeatureFlag(flag FeatureFlag) ([]byte, error) {
22 w := jwriter.NewWriter()
23 marshalFeatureFlagToWriter(flag, &w)
24 return w.Bytes(), w.Error()
25 }
26
27 func marshalFeatureFlagToWriter(flag FeatureFlag, w *jwriter.Writer) {
28 obj := w.Object()
29
30 obj.Name("key").String(flag.Key)
31
32 obj.Name("on").Bool(flag.On)
33
34 prereqsArr := obj.Name("prerequisites").Array()
35 for _, p := range flag.Prerequisites {
36 prereqObj := prereqsArr.Object()
37 prereqObj.Name("key").String(p.Key)
38 prereqObj.Name("variation").Int(p.Variation)
39 prereqObj.End()
40 }
41 prereqsArr.End()
42
43 writeTargets(&obj, flag.Targets, "targets")
44 writeTargets(&obj, flag.ContextTargets, "contextTargets")
45
46 rulesArr := obj.Name("rules").Array()
47 for _, r := range flag.Rules {
48 ruleObj := rulesArr.Object()
49 writeVariationOrRolloutProperties(&ruleObj, r.VariationOrRollout)
50 ruleObj.Maybe("id", r.ID != "").String(r.ID)
51 writeClauses(w, &ruleObj, r.Clauses)
52 ruleObj.Name("trackEvents").Bool(r.TrackEvents)
53 ruleObj.End()
54 }
55 rulesArr.End()
56
57 fallthroughObj := obj.Name("fallthrough").Object()
58 writeVariationOrRolloutProperties(&fallthroughObj, flag.Fallthrough)
59 fallthroughObj.End()
60
61 flag.OffVariation.WriteToJSONWriter(obj.Name("offVariation"))
62
63 variationsArr := obj.Name("variations").Array()
64 for _, v := range flag.Variations {
65 v.WriteToJSONWriter(w)
66 }
67 variationsArr.End()
68
69
70
71
72
73
74
75
76
77
78
79 if flag.ClientSideAvailability.Explicit {
80 csaObj := obj.Name("clientSideAvailability").Object()
81 csaObj.Name("usingMobileKey").Bool(flag.ClientSideAvailability.UsingMobileKey)
82 csaObj.Name("usingEnvironmentId").Bool(flag.ClientSideAvailability.UsingEnvironmentID)
83 csaObj.End()
84 }
85 obj.Name("clientSide").Bool(flag.ClientSideAvailability.UsingEnvironmentID)
86
87 obj.Name("salt").String(flag.Salt)
88
89 obj.Name("trackEvents").Bool(flag.TrackEvents)
90 obj.Name("trackEventsFallthrough").Bool(flag.TrackEventsFallthrough)
91
92 obj.Name("debugEventsUntilDate").Float64OrNull(flag.DebugEventsUntilDate != 0, float64(flag.DebugEventsUntilDate))
93
94 obj.Name("version").Int(flag.Version)
95
96 obj.Name("deleted").Bool(flag.Deleted)
97
98 obj.End()
99 }
100
101 func writeTargets(obj *jwriter.ObjectState, targets []Target, name string) {
102 targetsArr := obj.Name(name).Array()
103 for _, t := range targets {
104 targetObj := targetsArr.Object()
105 if t.ContextKind != "" {
106 targetObj.Name("contextKind").String(string(t.ContextKind))
107 }
108 targetObj.Name("variation").Int(t.Variation)
109 writeStringArray(&targetObj, "values", t.Values)
110 targetObj.End()
111 }
112 targetsArr.End()
113 }
114
115 func marshalSegment(segment Segment) ([]byte, error) {
116 w := jwriter.NewWriter()
117 marshalSegmentToWriter(segment, &w)
118 return w.Bytes(), w.Error()
119 }
120
121 func marshalSegmentToWriter(segment Segment, w *jwriter.Writer) {
122 obj := w.Object()
123
124 obj.Name("key").String(segment.Key)
125 writeStringArray(&obj, "included", segment.Included)
126 writeStringArray(&obj, "excluded", segment.Excluded)
127 writeSegmentTargets(&obj, segment.IncludedContexts, "includedContexts")
128 writeSegmentTargets(&obj, segment.ExcludedContexts, "excludedContexts")
129 obj.Name("salt").String(segment.Salt)
130
131 rulesArr := obj.Name("rules").Array()
132 for _, r := range segment.Rules {
133 ruleObj := rulesArr.Object()
134 ruleObj.Name("id").String(r.ID)
135 writeClauses(w, &ruleObj, r.Clauses)
136 ruleObj.Maybe("weight", r.Weight.IsDefined()).Int(r.Weight.IntValue())
137 writeAttrRef(ruleObj.Maybe("bucketBy", r.BucketBy.IsDefined()), &r.BucketBy, r.RolloutContextKind)
138 ruleObj.Maybe("rolloutContextKind", r.RolloutContextKind != "").String(string(r.RolloutContextKind))
139 ruleObj.End()
140 }
141 rulesArr.End()
142
143 obj.Maybe("unbounded", segment.Unbounded).Bool(segment.Unbounded)
144 obj.Maybe("unboundedContextKind", segment.UnboundedContextKind != "").String(string(segment.UnboundedContextKind))
145
146 obj.Name("version").Int(segment.Version)
147 segment.Generation.WriteToJSONWriter(obj.Name("generation"))
148 obj.Name("deleted").Bool(segment.Deleted)
149
150 obj.End()
151 }
152
153 func writeSegmentTargets(obj *jwriter.ObjectState, targets []SegmentTarget, name string) {
154 targetsArr := obj.Name(name).Array()
155 for _, t := range targets {
156 targetObj := targetsArr.Object()
157 if t.ContextKind != "" {
158 targetObj.Name("contextKind").String(string(t.ContextKind))
159 }
160 writeStringArray(&targetObj, "values", t.Values)
161 targetObj.End()
162 }
163 targetsArr.End()
164 }
165
166 func writeStringArray(obj *jwriter.ObjectState, name string, values []string) {
167 arr := obj.Name(name).Array()
168 for _, v := range values {
169 arr.String(v)
170 }
171 arr.End()
172 }
173
174 func writeVariationOrRolloutProperties(obj *jwriter.ObjectState, vr VariationOrRollout) {
175 obj.Maybe("variation", vr.Variation.IsDefined()).Int(vr.Variation.IntValue())
176 if len(vr.Rollout.Variations) > 0 {
177 rolloutObj := obj.Name("rollout").Object()
178 rolloutObj.Maybe("kind", vr.Rollout.Kind != "").String(string(vr.Rollout.Kind))
179 rolloutObj.Maybe("contextKind", vr.Rollout.ContextKind != "").String(string(vr.Rollout.ContextKind))
180 variationsArr := rolloutObj.Name("variations").Array()
181 for _, wv := range vr.Rollout.Variations {
182 variationObj := variationsArr.Object()
183 variationObj.Name("variation").Int(wv.Variation)
184 variationObj.Name("weight").Int(wv.Weight)
185 variationObj.Maybe("untracked", wv.Untracked).Bool(wv.Untracked)
186 variationObj.End()
187 }
188 variationsArr.End()
189 rolloutObj.Maybe("seed", vr.Rollout.Seed.IsDefined()).Int(vr.Rollout.Seed.IntValue())
190 writeAttrRef(rolloutObj.Maybe("bucketBy", vr.Rollout.BucketBy.IsDefined()),
191 &vr.Rollout.BucketBy, vr.Rollout.ContextKind)
192 rolloutObj.End()
193 }
194 }
195
196 func writeClauses(w *jwriter.Writer, obj *jwriter.ObjectState, clauses []Clause) {
197 clausesArr := obj.Name("clauses").Array()
198 for _, c := range clauses {
199 clauseObj := clausesArr.Object()
200 if c.ContextKind != "" {
201 clauseObj.Name("contextKind").String(string(c.ContextKind))
202 }
203
204 clauseObj.Name("attribute")
205 if !c.Attribute.IsDefined() {
206
207
208 w.String("")
209 } else {
210 writeAttrRef(w, &c.Attribute, c.ContextKind)
211 }
212
213 clauseObj.Name("op").String(string(c.Op))
214 valuesArr := clauseObj.Name("values").Array()
215 for _, v := range c.Values {
216 v.WriteToJSONWriter(w)
217 }
218 valuesArr.End()
219 clauseObj.Name("negate").Bool(c.Negate)
220 clauseObj.End()
221 }
222 clausesArr.End()
223 }
224
225 func writeAttrRef(w *jwriter.Writer, ref *ldattr.Ref, contextKind ldcontext.Kind) {
226 if contextKind == "" {
227
228
229
230
231 w.String(ref.Component(0))
232 } else {
233 w.String(ref.String())
234 }
235 }
236
View as plain text