public void UnmarshalAsSpecificType() { var jsonStr = "{\"key\":\"flag\",\"on\":false}"; var flag = FeatureStoreHelpers.UnmarshalJson(VersionedDataKind.Features, jsonStr); Assert.Equal("flag", flag.Key); }
public void UnmarshalAsGeneralType() { var jsonStr = "{\"key\":\"flag\",\"on\":false}"; IVersionedDataKind kind = VersionedDataKind.Features; var flag = FeatureStoreHelpers.UnmarshalJson(kind, jsonStr); Assert.Equal("flag", flag.Key); }
public void MarshalEntity() { var flag = new FeatureFlagBuilder("flag").Build(); var actualStr = FeatureStoreHelpers.MarshalJson(flag); var actualJson = JsonConvert.DeserializeObject <JObject>(actualStr); Assert.Equal("flag", (string)actualJson.GetValue("key")); }
public IVersionedData GetInternal(IVersionedDataKind kind, string key) { IDatabase db = _redis.GetDatabase(); string json = db.HashGet(ItemsKey(kind), key); if (json == null) { Log.DebugFormat("[get] Key: {0} not found in \"{1}\"", key, kind.GetNamespace()); return(null); } return(FeatureStoreHelpers.UnmarshalJson(kind, json)); }
public IDictionary <string, IVersionedData> GetAllInternal(IVersionedDataKind kind) { IDatabase db = _redis.GetDatabase(); HashEntry[] allEntries = db.HashGetAll(ItemsKey(kind)); Dictionary <string, IVersionedData> result = new Dictionary <string, IVersionedData>(); foreach (HashEntry entry in allEntries) { IVersionedData item = FeatureStoreHelpers.UnmarshalJson(kind, entry.Value); result[item.Key] = item; } return(result); }
public IVersionedData UpsertInternal(IVersionedDataKind kind, IVersionedData newItem) { IDatabase db = _redis.GetDatabase(); string baseKey = ItemsKey(kind); while (true) { string oldJson; try { oldJson = db.HashGet(baseKey, newItem.Key); } catch (RedisTimeoutException e) { Log.ErrorFormat("Timeout in update when reading {0} from {1}: {2}", newItem.Key, baseKey, e.ToString()); throw; } IVersionedData oldItem = (oldJson == null) ? null : FeatureStoreHelpers.UnmarshalJson(kind, oldJson); int oldVersion = (oldJson == null) ? -1 : oldItem.Version; if (oldVersion >= newItem.Version) { Log.DebugFormat("Attempted to {0} key: {1} version: {2} with a version that is" + " the same or older: {3} in \"{4}\"", newItem.Deleted ? "delete" : "update", newItem.Key, oldVersion, newItem.Version, kind.GetNamespace()); return(oldItem); } // This hook is used only in unit tests _updateHook?.Invoke(); // Note that transactions work a bit differently in StackExchange.Redis than in other // Redis clients. The same Redis connection is shared across all threads, so it can't // set a WATCH at the moment we start the transaction. Instead, it saves up all of // the actions we send during the transaction, and replays them all within a MULTI // when the transaction. AddCondition() is this client's way of doing a WATCH, and it // can only refer to the whole value, not to a JSON property of the value; that's why // we kept track of the whole value in "oldJson". ITransaction txn = db.CreateTransaction(); txn.AddCondition(oldJson == null ? Condition.HashNotExists(baseKey, newItem.Key) : Condition.HashEqual(baseKey, newItem.Key, oldJson)); txn.HashSetAsync(baseKey, newItem.Key, JsonConvert.SerializeObject(newItem)); try { bool success = txn.Execute(); if (!success) { // The watch was triggered, we should retry Log.Debug("Concurrent modification detected, retrying"); continue; } } catch (RedisTimeoutException e) { Log.ErrorFormat("Timeout on update of {0} in {1}: {2}", newItem.Key, baseKey, e.ToString()); throw; } return(newItem); } }