Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions dot-net/Centroid.Tests/ConfigTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ public void test_enumerating_json_object()
}
Assert.That(itemCount, Is.EqualTo(1));
}

[Test]
public void test_all_environment_is_not_case_sensitive()
{
Expand All @@ -154,5 +154,27 @@ public void test_all_environment_is_not_case_sensitive()
var lowerCaseAllEnvironmentConfig = lowerCaseAllConfig.ForEnvironment("Prod");
Assert.That(lowerCaseAllEnvironmentConfig.AllOnly, Is.EqualTo("works"));
}

[Test]
public void supports_deep_merge()
{
const string json = @"
{
""Dev"": {
""Database"": {
""Server"": ""the-dev-database""
}
},
""All"": {
""Database"": {
""MigrationsPath"": ""path/to/migrations""
}
}
}";

dynamic config = new Config(json).ForEnvironment("Dev");
Assert.That(config.Database.Server, Is.EqualTo("the-dev-database"));
Assert.That(config.Database.MigrationsPath, Is.EqualTo("path/to/migrations"));
}
}
}
}
34 changes: 30 additions & 4 deletions dot-net/Centroid/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,8 @@ public dynamic ForEnvironment(string environment)
return new Config(envConfig);
}

foreach (var cfg in envConfig)
{
allConfig[cfg.Name] = cfg.Value;
}
MergeInto(allConfig, envConfig);

return new Config(allConfig);
}

Expand Down Expand Up @@ -148,5 +146,33 @@ void ValidateUniqueKeys()
var keys = duplicates.SelectMany(d => d.Select(x => x.Key));
throw new InvalidOperationException("Centroid.Config instance contains duplicate keys: " + string.Join(", ", keys));
}

static void MergeInto(JContainer left, JToken right)
{
foreach (var rightChild in right.Children<JProperty>())
{
var rightChildProperty = rightChild;
var leftProperty = left.SelectToken(rightChildProperty.Name);

if (leftProperty == null)
{
left.Add(rightChild);
}
else
{
var leftObject = leftProperty as JObject;

if (leftObject == null)
{
var leftParent = (JProperty) leftProperty.Parent;
leftParent.Value = rightChildProperty.Value;
}
else
{
MergeInto(leftObject, rightChildProperty.Value);
}
}
}
}
}
}
13 changes: 11 additions & 2 deletions python/centroid.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,8 @@ def for_environment(self, env):
return Config(env_json)

all_json = _get_value(actual_key, self.raw_config)
all_json.update(env_json);

return Config(all_json)
return Config(_dict_merge(all_json, env_json))

@staticmethod
def from_file(filename):
Expand All @@ -75,3 +74,13 @@ def _get_actual_key(key, hashtable):
if len(result) > 0:
return result[0]
return None

def _dict_merge(left, right):
if not isinstance(right, dict):
return right
for k, v in right.iteritems():
if k in left and isinstance(left[k], dict):
left[k] = _dict_merge(left[k], v)
else:
left[k] = v
return left
6 changes: 6 additions & 0 deletions python/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,9 @@ def test_all_environment_is_not_case_sensitive(self):
config = Config('{"Prod": {"Shared": "production!"}, "all": {"Shared": "none", "AllOnly": "works"}}')
config = config.for_environment("Prod")
self.assertEqual(config.all_only, "works")

def test_supports_deep_merge(self):
config = Config('{"Prod": {"Database": {"Server": "prod-sql"}}, "All": {"Database": {"MigrationsPath": "path/to/migrations"}}}')
config = config.for_environment("Prod")
self.assertEqual(config.database.server, "prod-sql")
self.assertEqual(config.database.migrations_path, "path/to/migrations")
17 changes: 16 additions & 1 deletion ruby/lib/centroid.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def for_environment(env)
Config.new(env_json)
else
all_json = raw_config[all_key]
Config.new(all_json.merge(env_json))
Config.new(deep_merge(all_json, env_json))
end
end

Expand Down Expand Up @@ -72,5 +72,20 @@ def validate_unique_keys!
keys = dups.values.flat_map { |d| d.map { |e| e[:key] } }
raise KeyError, "Centroid::Config instance contains duplicate keys: #{keys.join(', ')}"
end

def deep_merge(left, right)
return right if not right.is_a?(Hash)

right.each_pair do |k, rv|
lv = left[k]
left[k] = if lv.is_a?(Hash) && rv.is_a?(Hash)
deep_merge(lv, rv)
else
rv
end
end

left
end
end
end
7 changes: 7 additions & 0 deletions ruby/test/centroid_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,11 @@ def test_all_environment_is_not_case_sensitive
config = config.for_environment("Prod")
assert_equal(config.all_only, "works")
end

def test_supports_deep_merge
config = Centroid::Config.new('{"Prod": {"Database": {"Server": "prod-sql"}}, "All": {"Database": {"MigrationsPath": "path/to/migrations"}}}')
config = config.for_environment("Prod")
assert_equal(config.database.server, "prod-sql")
assert_equal(config.database.migrations_path, "path/to/migrations")
end
end