Skip to content

Commit

Permalink
feat: dictionary implementation (#88)
Browse files Browse the repository at this point in the history
This PR:

Creates a separate incubating client
Implements the core dictionary functionality (DictionarySet, DictionaryGet, DictionaryDelete, DictionaryRemoveField and their multi counterparts).
For the dictionary implementation, we created a separate incubating client. In the future the incubating client will be in a separate repository; for now it is in a separate namespace. In preparation for this we made the incubating client only depend on a client interface. This interface defines the contract that a production client should implement. We chose this pattern as opposed to inheritance or reflection to: (1) loosely couple the incubating client to the production one, and (2) to be able to have client documentation available to both the production and incubating clients.

To limit accessibility of internal code, we refactored to a separate namespace. To share with the incubating client, we increased visibility where necessary.

In preparation for the repository split, the incubating client has its own set of integration tests
  • Loading branch information
malandis authored Jul 29, 2022
1 parent 37bec19 commit c040694
Show file tree
Hide file tree
Showing 31 changed files with 3,414 additions and 670 deletions.
1,347 changes: 1,347 additions & 0 deletions IncubatingIntegrationTest/DictionaryTest.cs

Large diffs are not rendered by default.

54 changes: 54 additions & 0 deletions IncubatingIntegrationTest/Fixtures.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
namespace IncubatingIntegrationTest;

/// <summary>
/// A cache client fixture.
/// Use this when not testing client-building edge cases:
/// re-using the client drops overall integration test time down ~5X.
/// </summary>
public class SimpleCacheClientFixture : IDisposable
{
public SimpleCacheClient Client { get; private set; }
public string AuthToken { get; private set; }

// TODO: this cache was specially created for this.
// We will not programmatically create integration test cache for now.
public const string CacheName = "client-sdk-csharp-incubating";
public const uint DefaultTtlSeconds = 10;

public SimpleCacheClientFixture()
{
AuthToken = Environment.GetEnvironmentVariable("TEST_AUTH_TOKEN") ??
throw new NullReferenceException("TEST_AUTH_TOKEN environment variable must be set.");
Client = SimpleCacheClientFactory.CreateClient(AuthToken, defaultTtlSeconds: DefaultTtlSeconds);

/*
try
{
Client.CreateCache(CacheName);
}
catch (AlreadyExistsException)
{
}*/

if (!Client.ListCaches().Caches.Contains(new MomentoSdk.Responses.CacheInfo(CacheName)))
{
throw new NotFoundException($"Cache {CacheName} not found. This is assumed to exist and have a BlobDb partition.");
}
}

public void Dispose()
{
// TODO cleanup
//Client.DeleteCache(CacheName);
Client.Dispose();
}
}

/// <summary>
/// Register the fixture in xUnit.
/// </summary>
[CollectionDefinition("SimpleCacheClient")]
public class SimpleCacheClientCollection : ICollectionFixture<SimpleCacheClientFixture>
{

}
28 changes: 28 additions & 0 deletions IncubatingIntegrationTest/IncubatingIntegrationTest.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Momento\MomentoSdk.csproj" />
</ItemGroup>

</Project>
4 changes: 4 additions & 0 deletions IncubatingIntegrationTest/Usings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
global using Xunit;
global using MomentoSdk.Incubating;
global using MomentoSdk.Exceptions;
global using Utils = MomentoSdk.Internal.Utils;
6 changes: 6 additions & 0 deletions Momento.sln
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MomentoTest", "MomentoTest\
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MomentoIntegrationTest", "MomentoIntegrationTest\MomentoIntegrationTest.csproj", "{FB56314E-BDCF-474A-A2CD-8956934FF11B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IncubatingIntegrationTest", "IncubatingIntegrationTest\IncubatingIntegrationTest.csproj", "{A0F6221C-42A9-454B-BB82-EDB9841DF6E1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -27,6 +29,10 @@ Global
{FB56314E-BDCF-474A-A2CD-8956934FF11B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FB56314E-BDCF-474A-A2CD-8956934FF11B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FB56314E-BDCF-474A-A2CD-8956934FF11B}.Release|Any CPU.Build.0 = Release|Any CPU
{A0F6221C-42A9-454B-BB82-EDB9841DF6E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A0F6221C-42A9-454B-BB82-EDB9841DF6E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A0F6221C-42A9-454B-BB82-EDB9841DF6E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A0F6221C-42A9-454B-BB82-EDB9841DF6E1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
248 changes: 248 additions & 0 deletions Momento/ISimpleCacheClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using MomentoSdk.Responses;
namespace MomentoSdk;

public interface ISimpleCacheClient : IDisposable
{
/// <summary>
/// Creates a cache if it doesn't exist.
/// </summary>
/// <param name="cacheName">Name of the cache to be created.</param>
/// <returns>The result of the create cache operation</returns>
public CreateCacheResponse CreateCache(string cacheName);

/// <summary>
/// Deletes a cache and all of the items within it.
/// </summary>
/// <param name="cacheName">Name of the cache to be deleted.</param>
/// <returns>Result of the delete cache operation.</returns>
public DeleteCacheResponse DeleteCache(string cacheName);

/// <summary>
/// List all caches.
/// </summary>
/// <param name="nextPageToken">A token to specify where to start paginating. This is the NextToken from a previous response.</param>
/// <returns>Result of the list cache operation.</returns>
public ListCachesResponse ListCaches(string? nextPageToken = null);

/// <summary>
/// Set the value in cache with a given time to live (TTL) seconds.
/// </summary>
/// <param name="cacheName">Name of the cache to store the item in.</param>
/// <param name="key">The key to set.</param>
/// <param name="value">The value to be stored.</param>
/// <param name="ttlSeconds">TTL for the item in cache. This TTL takes precedence over the TTL used when initializing a cache client. Defaults to client TTL.</param>
/// <returns>Task object representing the result of the set operation.</returns>
public Task<CacheSetResponse> SetAsync(string cacheName, byte[] key, byte[] value, uint? ttlSeconds = null);

/// <summary>
/// Get the cache value stored for the given key.
/// </summary>
/// <param name="cacheName">Name of the cache to perform the lookup in.</param>
/// <param name="key">The key to lookup.</param>
/// <returns>Task object containing the status of the get operation and the associated value.</returns>
public Task<CacheGetResponse> GetAsync(string cacheName, byte[] key);

/// <summary>
/// Remove the key from the cache.
/// </summary>
/// <param name="cacheName">Name of the cache to delete the key from.</param>
/// <param name="key">The key to delete.</param>
/// <returns>Task object representing the result of the delete operation.</returns>
public Task<CacheDeleteResponse> DeleteAsync(string cacheName, byte[] key);

/// <summary>
/// Set the value in cache with a given time to live (TTL) seconds.
/// </summary>
/// <param name="cacheName">Name of the cache to store the item in.</param>
/// <param name="key">The key to set.</param>
/// <param name="value">The value to be stored.</param>
/// <param name="ttlSeconds">TTL for the item in cache. This TTL takes precedence over the TTL used when initializing a cache client. Defaults to client TTL.</param>
/// <returns>Task object representing the result of the set operation.</returns>
public Task<CacheSetResponse> SetAsync(string cacheName, string key, string value, uint? ttlSeconds = null);

/// <summary>
/// Get the cache value stored for the given key.
/// </summary>
/// <param name="cacheName">Name of the cache to perform the lookup in.</param>
/// <param name="key">The key to lookup.</param>
/// <returns>Task object representing containing the status of the get operation and the associated value.</returns>
public Task<CacheGetResponse> GetAsync(string cacheName, string key);

/// <summary>
/// Remove the key from the cache.
/// </summary>
/// <param name="cacheName">Name of the cache to delete the key from.</param>
/// <param name="key">The key to delete.</param>
/// <returns>Task object representing the result of the delete operation.</returns>
public Task<CacheDeleteResponse> DeleteAsync(string cacheName, string key);

/// <summary>
/// Set the value in cache with a given time to live (TTL) seconds.
/// </summary>
/// <param name="cacheName">Name of the cache to store the item in.</param>
/// <param name="key">The key to set.</param>
/// <param name="value">The value to be stored.</param>
/// <param name="ttlSeconds">TTL for the item in cache. This TTL takes precedence over the TTL used when initializing a cache client. Defaults to client TTL.</param>
/// <returns>Task object representing the result of the set operation.</returns>
public Task<CacheSetResponse> SetAsync(string cacheName, string key, byte[] value, uint? ttlSeconds = null);

/// <summary>
/// Gets multiple values from the cache.
/// </summary>
/// <param name="cacheName">Name of the cache to perform the lookup in.</param>
/// <param name="keys">The keys to get.</param>
/// <returns>Task object representing the statuses of the get operation and the associated values.</returns>
public Task<CacheGetMultiResponse> GetMultiAsync(string cacheName, IEnumerable<byte[]> keys);

/// <summary>
/// Gets multiple values from the cache.
/// </summary>
/// <param name="cacheName">Name of the cache to perform the lookup in.</param>
/// <param name="keys">The keys to get.</param>
/// <returns>Task object representing the statuses of the get operation and the associated values.</returns>
public Task<CacheGetMultiResponse> GetMultiAsync(string cacheName, IEnumerable<string> keys);

/// <summary>
/// Gets multiple values from the cache.
/// </summary>
/// <param name="cacheName">Name of the cache to perform the lookup in.</param>
/// <param name="keys">The keys to get.</param>
/// <returns>Task object representing the statuses of the get operation and the associated values.</returns>
public Task<CacheGetMultiResponse> GetMultiAsync(string cacheName, params byte[][] keys);

/// <summary>
/// Gets multiple values from the cache.
/// </summary>
/// <param name="cacheName">Name of the cache to perform the lookup in.</param>
/// <param name="keys">The keys to get.</param>
/// <returns>Task object representing the statuses of the get operation and the associated values.</returns>
public Task<CacheGetMultiResponse> GetMultiAsync(string cacheName, params string[] keys);

/// <summary>
/// Sets multiple items in the cache. Overwrites existing items.
/// </summary>
/// <param name="cacheName">Name of the cache to store the items in.</param>
/// <param name="items">The items to set.</param>
/// <returns>Task object representing the result of the set operation.</returns>
public Task<CacheSetMultiResponse> SetMultiAsync(string cacheName, IDictionary<byte[], byte[]> items, uint? ttlSeconds = null);

/// <summary>
/// Sets multiple items in the cache. Overwrites existing items.
/// </summary>
/// <param name="cacheName">Name of the cache to store the items in.</param>
/// <param name="items">The items to set.</param>
/// <returns>Task object representing the result of the set operation.</returns>
public Task<CacheSetMultiResponse> SetMultiAsync(string cacheName, IDictionary<string, string> items, uint? ttlSeconds = null);

/// <summary>
/// Set the value in the cache. If a value for this key is already present it will be replaced by the new value.
/// </summary>
/// <param name="cacheName">Name of the cache to store the item in.</param>
/// <param name="key">The key to set.</param>
/// <param name="value">The value to be stored.</param>
/// <param name="ttlSeconds">Time to live (TTL) for the item in Cache. This TTL takes precedence over the TTL used when initializing a cache client. Defaults to client TTL.</param>
/// <returns>Result of the set operation.</returns>
public CacheSetResponse Set(string cacheName, byte[] key, byte[] value, uint? ttlSeconds = null);

/// <summary>
/// Get the cache value stored for the given key.
/// </summary>
/// <param name="cacheName">Name of the cache to perform the lookup in.</param>
/// <param name="key">The key to lookup.</param>
/// <returns>Object with the status of the get operation and the associated value.</returns>
public CacheGetResponse Get(string cacheName, byte[] key);

/// <summary>
/// Remove the key from the cache.
/// </summary>
/// <param name="cacheName">Name of the cache to delete the key from.</param>
/// <param name="key">The key to delete.</param>
/// <returns>Result of the delete operation.</returns>
public CacheDeleteResponse Delete(string cacheName, byte[] key);

/// <summary>
/// Set the value in cache with a given time to live (TTL) seconds. If a value for this key is already present it will be replaced by the new value.
/// </summary>
/// <param name="key">The key to set.</param>
/// <param name="value">The value to be stored.</param>
/// <param name="ttlSeconds">TTL for the item in cache. This TTL takes precedence over the TTL used when initializing a cache client. Defaults to client TTL.</param>
/// <returns>Result of the set operation.</returns>
public CacheSetResponse Set(string cacheName, string key, string value, uint? ttlSeconds = null);

/// <summary>
/// Get the cache value stored for the given key.
/// </summary>
/// <param name="cacheName">Name of the cache to perform the lookup in.</param>
/// <param name="key">The key to lookup.</param>
/// <returns>Object with the status of the get operation and the associated value.</returns>
public CacheGetResponse Get(string cacheName, string key);

/// <summary>
/// Gets multiple values from the cache.
/// </summary>
/// <param name="cacheName">Name of the cache to perform the lookup in.</param>
/// <param name="keys">The keys to get.</param>
/// <returns>Object with the statuses of the get operation and the associated values.</returns>
public CacheGetMultiResponse GetMulti(string cacheName, IEnumerable<byte[]> keys);

/// <summary>
/// Gets multiple values from the cache.
/// </summary>
/// <param name="cacheName">Name of the cache to perform the lookup in.</param>
/// <param name="keys">The keys to get.</param>
/// <returns>Object with the statuses of the get operation and the associated values.</returns>
public CacheGetMultiResponse GetMulti(string cacheName, IEnumerable<string> keys);

/// <summary>
/// Gets multiple values from the cache.
/// </summary>
/// <param name="cacheName">Name of the cache to perform the lookup in.</param>
/// <param name="keys">The keys to get.</param>
/// <returns>Object with the statuses of the get operation and the associated values.</returns>
public CacheGetMultiResponse GetMulti(string cacheName, params byte[][] keys);

/// <summary>
/// Gets multiple values from the cache.
/// </summary>
/// <param name="cacheName">Name of the cache to perform the lookup in.</param>
/// <param name="keys">The keys to get.</param>
/// <returns>Object with the statuses of the get operation and the associated values.</returns>
public CacheGetMultiResponse GetMulti(string cacheName, params string[] keys);

/// <summary>
/// Sets multiple items in the cache. Overwrites existing items.
/// </summary>
/// <param name="cacheName">Name of the cache to store the items in.</param>
/// <param name="items">The items to set.</param>
/// <returns>Result of the set operation.</returns>
public CacheSetMultiResponse SetMulti(string cacheName, IDictionary<byte[], byte[]> items, uint? ttlSeconds = null);

/// <summary>
/// Sets multiple items in the cache. Overwrites existing items.
/// </summary>
/// <param name="cacheName">Name of the cache to store the items in.</param>
/// <param name="items">The items to set.</param>
/// <returns>Result of the set operation.</returns>
public CacheSetMultiResponse SetMulti(string cacheName, IDictionary<string, string> items, uint? ttlSeconds = null);

/// <summary>
/// Remove the key from the cache.
/// </summary>
/// <param name="cacheName">Name of the cache to delete the key from.</param>
/// <param name="key">The key to delete.</param>
/// <returns>Result of the delete operation.</returns>
public CacheDeleteResponse Delete(string cacheName, string key);

/// <summary>
/// Set the value in cache with a given time to live (TTL) seconds. If a value for this key is already present it will be replaced by the new value.
/// </summary>
/// <param name="cacheName">Name of the cache to store the item in.</param>
/// <param name="key">The key to set.</param>
/// <param name="value">The value to be stored.</param>
/// <param name="ttlSeconds">TTL for the item in cache. This TTL takes precedence over the TTL used when initializing a cache client. Defaults to client TTL.</param>
/// <returns>Result of the set operation</returns>
public CacheSetResponse Set(string cacheName, string key, byte[] value, uint? ttlSeconds = null);
}
Loading

0 comments on commit c040694

Please sign in to comment.