Skip to content

Commit 595f91a

Browse files
authored
chore: Switch to using symbols in FDv2 for consistency with v1 (#354)
fix: Update feature store interface doc to align with existing code that expects symbols not strings
1 parent add7638 commit 595f91a

16 files changed

Lines changed: 473 additions & 115 deletions

lib/ldclient-rb/impl/data_store/in_memory_feature_store.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def get(kind, key)
2828
items_of_kind = @items[kind]
2929
return nil if items_of_kind.nil?
3030

31-
item = items_of_kind[key]
31+
item = items_of_kind[key.to_sym]
3232
return nil if item.nil?
3333
return nil if item[:deleted]
3434

lib/ldclient-rb/impl/data_store/store.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ def get_data_store_status_provider
284284
# Convert a list of Changes to the pre-existing format used by FeatureStore.
285285
#
286286
# @param changes [Array<LaunchDarkly::Interfaces::DataSystem::Change>] List of changes
287-
# @return [Hash{DataKind => Hash{String => Hash}}] Hash suitable for FeatureStore operations
287+
# @return [Hash{DataKind => Hash{Symbol => Hash}}] Hash suitable for FeatureStore operations
288288
#
289289
private def changes_to_store_data(changes)
290290
all_data = {
@@ -307,7 +307,7 @@ def get_data_store_status_provider
307307
#
308308
# Reset dependency tracker with new full data set.
309309
#
310-
# @param all_data [Hash{DataKind => Hash{String => Hash}}] Hash of data kinds to items
310+
# @param all_data [Hash{DataKind => Hash{Symbol => Hash}}] Hash of data kinds to items
311311
# @return [void]
312312
#
313313
private def reset_dependency_tracker(all_data)

lib/ldclient-rb/impl/data_system/polling.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ def self.fdv1_polling_payload_to_changeset(data)
516516
version = flag_or_segment[:version]
517517
return LaunchDarkly::Result.fail("Invalid format: #{key} does not have a version set") if version.nil?
518518

519-
builder.add_put(kind, key.to_s, version, flag_or_segment)
519+
builder.add_put(kind, key, version, flag_or_segment)
520520
end
521521
end
522522

lib/ldclient-rb/impl/data_system/protocolv2.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ class DeleteObject
2222
# @return [String] The object kind ({LaunchDarkly::Interfaces::DataSystem::ObjectKind})
2323
attr_reader :kind
2424

25-
# @return [String] The key
25+
# @return [Symbol] The key
2626
attr_reader :key
2727

2828
#
2929
# @param version [Integer] The version
3030
# @param kind [String] The object kind ({LaunchDarkly::Interfaces::DataSystem::ObjectKind})
31-
# @param key [String] The key
31+
# @param key [Symbol] The key
3232
#
3333
def initialize(version:, kind:, key:)
3434
@version = version
@@ -72,7 +72,7 @@ def self.from_h(data)
7272

7373
raise ArgumentError, "Missing required fields in DeleteObject" if version.nil? || kind.nil? || key.nil?
7474

75-
new(version: version, kind: kind, key: key)
75+
new(version: version, kind: kind, key: key.to_sym)
7676
end
7777
end
7878

@@ -89,7 +89,7 @@ class PutObject
8989
# @return [String] The object kind ({LaunchDarkly::Interfaces::DataSystem::ObjectKind})
9090
attr_reader :kind
9191

92-
# @return [String] The key
92+
# @return [Symbol] The key
9393
attr_reader :key
9494

9595
# @return [Hash] The object data
@@ -98,7 +98,7 @@ class PutObject
9898
#
9999
# @param version [Integer] The version
100100
# @param kind [String] The object kind ({LaunchDarkly::Interfaces::DataSystem::ObjectKind})
101-
# @param key [String] The key
101+
# @param key [Symbol] The key
102102
# @param object [Hash] The object data
103103
#
104104
def initialize(version:, kind:, key:, object:)
@@ -146,7 +146,7 @@ def self.from_h(data)
146146

147147
raise ArgumentError, "Missing required fields in PutObject" if version.nil? || kind.nil? || key.nil? || object_data.nil?
148148

149-
new(version: version, kind: kind, key: key, object: object_data)
149+
new(version: version, kind: kind, key: key.to_sym, object: object_data)
150150
end
151151
end
152152

lib/ldclient-rb/impl/integrations/test_data/test_data_source_v2.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,9 +192,10 @@ def upsert_flag(flag_data)
192192
builder.start(LaunchDarkly::Interfaces::DataSystem::IntentCode::TRANSFER_CHANGES)
193193

194194
# Add the updated flag
195+
flag_key = flag_data[:key].to_sym
195196
builder.add_put(
196197
LaunchDarkly::Interfaces::DataSystem::ObjectKind::FLAG,
197-
flag_data[:key],
198+
flag_key,
198199
flag_data[:version] || 1,
199200
flag_data
200201
)
@@ -247,9 +248,10 @@ def upsert_segment(segment_data)
247248
builder.start(LaunchDarkly::Interfaces::DataSystem::IntentCode::TRANSFER_CHANGES)
248249

249250
# Add the updated segment
251+
segment_key = segment_data[:key].to_sym
250252
builder.add_put(
251253
LaunchDarkly::Interfaces::DataSystem::ObjectKind::SEGMENT,
252-
segment_data[:key],
254+
segment_key,
253255
segment_data[:version] || 1,
254256
segment_data
255257
)

lib/ldclient-rb/impl/store_data_set_sorter.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def self.sort_collection(kind, input)
3535
items_out = {}
3636
until remaining_items.empty?
3737
# pick a random item that hasn't been updated yet
38-
key, item = remaining_items.first
38+
_, item = remaining_items.first
3939
self.add_with_dependencies_first(item, dependency_fn, remaining_items, items_out)
4040
end
4141
items_out

lib/ldclient-rb/integrations/test_data_v2.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,13 @@ def update(flag_builder)
117117
instances_copy = []
118118
new_flag = nil
119119
@lock.with_write_lock do
120-
old_flag = @current_flags[flag_builder._key]
120+
flag_key = flag_builder._key.to_sym
121+
old_flag = @current_flags[flag_key]
121122
old_version = old_flag ? old_flag[:version] : 0
122123

123124
new_flag = flag_builder.build(old_version + 1)
124125

125-
@current_flags[flag_builder._key] = new_flag
126+
@current_flags[flag_key] = new_flag
126127
@flag_builders[flag_builder._key] = flag_builder.clone
127128

128129
# Create a copy of instances while holding the lock to avoid race conditions
@@ -200,7 +201,7 @@ def use_preconfigured_segment(segment)
200201
else
201202
segment.as_json
202203
end
203-
segment_key = segment_hash[:key]
204+
segment_key = segment_hash[:key].to_sym
204205

205206
old_segment = @current_segments[segment_key]
206207
old_version = old_segment ? old_segment[:version] : 0

lib/ldclient-rb/interfaces/data_system.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ class Change
227227
# @return [String] The kind ({ObjectKind})
228228
attr_reader :kind
229229

230-
# @return [String] The key
230+
# @return [Symbol] The key
231231
attr_reader :key
232232

233233
# @return [Integer] The version
@@ -239,7 +239,7 @@ class Change
239239
#
240240
# @param action [String] The action type ({ChangeType})
241241
# @param kind [String] The object kind ({ObjectKind})
242-
# @param key [String] The key
242+
# @param key [Symbol] The key
243243
# @param version [Integer] The version
244244
# @param object [Hash, nil] The object data
245245
#
@@ -546,7 +546,7 @@ def finish(selector)
546546
# Adds a new object to the changeset.
547547
#
548548
# @param kind [String] The object kind ({ObjectKind})
549-
# @param key [String] The key
549+
# @param key [Symbol] The key
550550
# @param version [Integer] The version
551551
# @param obj [Hash] The object data
552552
# @return [void]
@@ -565,7 +565,7 @@ def add_put(kind, key, version, obj)
565565
# Adds a deletion to the changeset.
566566
#
567567
# @param kind [String] The object kind ({ObjectKind})
568-
# @param key [String] The key
568+
# @param key [Symbol] The key
569569
# @param version [Integer] The version
570570
# @return [void]
571571
#

lib/ldclient-rb/interfaces/feature_store.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ module FeatureStore
3636
# the correct order), storing each item, and then delete any leftover items at the very end.
3737
#
3838
# @param all_data [Hash] a hash where each key is one of the data kind objects, and each
39-
# value is in turn a hash of string keys to entities
39+
# value is in turn a hash of symbol keys to entities
4040
# @return [void]
4141
#
4242
def init(all_data)
@@ -46,7 +46,7 @@ def init(all_data)
4646
# Returns the entity to which the specified key is mapped, if any.
4747
#
4848
# @param kind [Object] the kind of entity to get
49-
# @param key [String] the unique key of the entity to get
49+
# @param key [String, Symbol] the unique key of the entity to get
5050
# @return [Hash] the entity; nil if the key was not found, or if the stored entity's
5151
# `:deleted` property was true
5252
#
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
require "spec_helper"
2+
require "ldclient-rb/impl/data_store/in_memory_feature_store"
3+
require "ldclient-rb/impl/data_store"
4+
5+
module LaunchDarkly
6+
module Impl
7+
module DataStore
8+
describe InMemoryFeatureStoreV2 do
9+
let(:logger) { double.as_null_object }
10+
subject { InMemoryFeatureStoreV2.new(logger) }
11+
12+
let(:flag_key) { "test-flag" }
13+
let(:flag) do
14+
{
15+
key: flag_key,
16+
version: 1,
17+
on: true,
18+
fallthrough: { variation: 0 },
19+
variations: [true, false],
20+
}
21+
end
22+
23+
describe "#get with string/symbol key compatibility" do
24+
before do
25+
# Store items with symbol keys (as done by FDv2 protocol layer)
26+
collections = {
27+
FEATURES => { flag_key.to_sym => flag },
28+
}
29+
subject.set_basis(collections)
30+
end
31+
32+
it "retrieves items with string keys (critical for variation calls)" do
33+
result = subject.get(FEATURES, flag_key)
34+
expect(result).to be_a(LaunchDarkly::Impl::Model::FeatureFlag)
35+
expect(result.key).to eq(flag_key)
36+
end
37+
38+
it "retrieves items with symbol keys" do
39+
result = subject.get(FEATURES, flag_key.to_sym)
40+
expect(result).to be_a(LaunchDarkly::Impl::Model::FeatureFlag)
41+
expect(result.key).to eq(flag_key)
42+
end
43+
44+
it "returns nil for non-existent keys" do
45+
expect(subject.get(FEATURES, "nonexistent")).to be_nil
46+
end
47+
end
48+
end
49+
end
50+
end
51+
end

0 commit comments

Comments
 (0)