Skip to content

Commit

Permalink
Upgrade Cosmos SDK
Browse files Browse the repository at this point in the history
Upgrade .NET Dependencies
Improve ClientBuilder options
Fix Direct Get()
Add Count() to IRepository
Add ResolveCount to ICosmosDbContainer
  • Loading branch information
william-liebenberg committed Oct 4, 2021
1 parent 0548ac1 commit a18cc85
Show file tree
Hide file tree
Showing 17 changed files with 290 additions and 76 deletions.
9 changes: 4 additions & 5 deletions AzureGems.CosmosDB/AzureGems.CosmosDB.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,10 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.16.0" />
<PackageReference Include="Microsoft.Azure.Cosmos.Direct" Version="3.11.4" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.9" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.9" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.9" />
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.21.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.19" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.19" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.19" />
</ItemGroup>

<ItemGroup>
Expand Down
89 changes: 60 additions & 29 deletions AzureGems.CosmosDB/CosmosDbClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace AzureGems.CosmosDB
{
public class CosmosDbClient : ICosmosDbClient, IDisposable
{
private readonly ContainerDefinition[] _containerDefinitions;
private readonly List<ContainerDefinition> _containerDefinitions = new List<ContainerDefinition>();

private readonly CosmosClient _sdkClient;
private readonly AsyncLazy<Database> _lazyDatabase;
Expand All @@ -23,43 +23,49 @@ private async Task<Database> GetDatabase()

private readonly ConcurrentDictionary<string, ICosmosDbContainer> _containerCache = new ConcurrentDictionary<string, ICosmosDbContainer>();

public IEnumerable<ContainerDefinition> ContainerDefinitions { get { return _containerDefinitions; } }

public void AddContainerDefinition(ContainerDefinition containerDefinition)
{
ContainerDefinition existing = GetContainerDefinition(containerDefinition.ContainerId);
//ContainerDefinition existing = GetContainerDefinitionForType(containerDefinition.EntityType);
if (existing is null)
{
_containerDefinitions.Add(containerDefinition);
return;
}

throw new NotImplementedException();
}

public async Task<ICosmosDbContainer> CreateContainer(ContainerDefinition containerDefinition)
{
return await _containerCache.GetOrAddAsync(containerDefinition.ContainerId, async id =>
{
Container cosmosSdkContainer = await Internal_GetContainer(containerDefinition.ContainerId);
//ContainerDefinition definition = GetContainerDefinitionForType(containerDefinition.EntityType);
ContainerDefinition definition = GetContainerDefinition(containerDefinition.ContainerId);
var container = new CosmosDbContainer(definition, this, cosmosSdkContainer);

if (_containerFactory != null)
{
return _containerFactory.Create(container);
}
else
{
// Container cosmosSdkContainer = await Internal_GetContainer(containerDefinition.ContainerId);
Container cosmosSdkContainer = await Internal_EnsureContainerExists(await this.GetDatabase(), containerDefinition);

return container;
}
var container = new CosmosDbContainer(definition, this, cosmosSdkContainer);

return _containerFactory == null ? container : _containerFactory.Create(container);
});
}

public ContainerDefinition GetContainerDefinition(string containerId)
{
ContainerDefinition containerDef = _containerDefinitions.First(def => def.ContainerId == containerId);
ContainerDefinition containerDef = _containerDefinitions.FirstOrDefault(def => def.ContainerId == containerId);
return containerDef;
}

public ContainerDefinition GetContainerDefinitionForType(Type t)
{
ContainerDefinition containerDefForT = _containerDefinitions.First(def => def.EntityType == t);
ContainerDefinition containerDefForT = _containerDefinitions.FirstOrDefault(def => def.EntityType == t);
return containerDefForT;
}

public ContainerDefinition GetContainerDefinitionForType<T>()
{
Type t = typeof(T);
return GetContainerDefinitionForType(t);
}

public CosmosDbClient(
CosmosDbConnectionSettings connectionSettings,
Expand All @@ -70,14 +76,14 @@ public CosmosDbClient(
_containerFactory = containerFactory;

IEnumerable<ContainerDefinition> definitions = containerDefinitions as ContainerDefinition[] ?? containerDefinitions.ToArray();
_containerDefinitions = definitions.ToArray();
_containerDefinitions.AddRange(definitions);

_sdkClient = new CosmosClient(
connectionSettings.EndPoint,
connectionSettings.AuthKey,
new CosmosClientOptions()
{
ConnectionMode = ConnectionMode.Direct,
ConnectionMode = cosmosDbConfig.ConnectionMode,
SerializerOptions = new CosmosSerializationOptions()
{
IgnoreNullValues = true,
Expand Down Expand Up @@ -107,12 +113,19 @@ private static async Task<Container> Internal_EnsureContainerExists(Database db,
{
var containerDefinition = new ContainerProperties(id: containerId, partitionKeyPath: partitionKeyPath);

ContainerResponse response = await db.CreateContainerIfNotExistsAsync(
containerProperties: containerDefinition,
throughput: throughput,
requestOptions: null);

return response.Container;
try
{
ContainerResponse response = await db.CreateContainerIfNotExistsAsync(
containerProperties: containerDefinition,
throughput: throughput,
requestOptions: null);

return response.Container;
}
catch(CosmosException cex)
{
throw;
}
}

private async Task<Container> Internal_GetContainer(string containerId)
Expand All @@ -124,14 +137,32 @@ private async Task<Container> Internal_GetContainer(string containerId)

public async Task<ICosmosDbContainer> GetContainer(string containerId)
{
// TODO: Avoid searching for container via ID, prefer type instead
ContainerDefinition definition = GetContainerDefinition(containerId);
return await this.CreateContainer(definition);
}

public async Task<ICosmosDbContainer> GetContainer<TEntity>()
public async Task<bool> DeleteContainer(ContainerDefinition containerDefinition)
{
ContainerDefinition definition = GetContainerDefinitionForType<TEntity>();
return await GetContainer(definition.ContainerId);
Container sdkContainer = await Internal_GetContainer(containerDefinition.ContainerId);
var sdkResponse = await sdkContainer.DeleteContainerAsync();
var deleteResponse = sdkResponse.ToCosmosDbResponse();
if(!deleteResponse.IsSuccessful)
{
// TODO: need logging
// TODO: throw exception?
return false;
}

if(_containerCache.TryRemove(containerDefinition.ContainerId, out ICosmosDbContainer removedContainer))
{
// container was removed from cache successfully
return true;
}

// container was not removed from cache...but do we really care?
// TODO: do we care if cache entry is not removed properly?
return true;
}

public void Dispose()
Expand Down
15 changes: 14 additions & 1 deletion AzureGems.CosmosDB/CosmosDbClientBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using Microsoft.Azure.Cosmos;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

Expand All @@ -9,7 +10,7 @@ public class CosmosDbClientBuilder
{
private readonly List<ContainerDefinition> _containerDefinitions = new List<ContainerDefinition>();
private CosmosDbConnectionSettings _connectionSettings = null;
private CosmosDbDatabaseSettings _dbconfig = new CosmosDbDatabaseSettings(null, null);
private CosmosDbDatabaseSettings _dbconfig = new CosmosDbDatabaseSettings(null, null, ConnectionMode.Gateway);
private ICosmosDbContainerFactory _containerFactory = null;

public CosmosDbClientBuilder()
Expand All @@ -36,6 +37,18 @@ public CosmosDbClientBuilder WithContainerFactory(ICosmosDbContainerFactory cont
return this;
}

public CosmosDbClientBuilder UseDirectMode()
{
_dbconfig.ConnectionMode = ConnectionMode.Direct;
return this;
}

public CosmosDbClientBuilder UseGatewayMode()
{
_dbconfig.ConnectionMode = ConnectionMode.Gateway;
return this;
}

public CosmosDbClientBuilder UseDatabase(string databaseId)
{
_dbconfig.DatabaseId = databaseId;
Expand Down
Loading

0 comments on commit a18cc85

Please sign in to comment.