Skip to content

Commit

Permalink
Merge branch 'release/universe-1.4.0' into prod
Browse files Browse the repository at this point in the history
  • Loading branch information
kuromukira committed Oct 20, 2022
2 parents d9e0666 + 7665ba3 commit c0b5b44
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 37 deletions.
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class MyCosmosEntity : ICosmicEntity
public DateTime AddedOn { get; set; }
public DateTime ModifiedOn { get; set; }

[JsonIgnore]
public string PartitionKey => FirstName;
}
```
Expand All @@ -23,7 +24,15 @@ public class MyCosmosEntity : ICosmicEntity
```csharp
public class MyRepository : Galaxy<MyModel>
{
public MyRepository(Database db, string container, string partitionKey) : base(db, container, partitionKey)
public MyRepository(CosmosClient client, string database, string container, string partitionKey) : base(client, database, container, partitionKey)
{
}
}

// If you want to see debug information such as the full Query text executed, use the format below:
public class MyRepository : Galaxy<MyModel>
{
public MyRepository(CosmosClient client, string database, string container, string partitionKey) : base(client, database, container, partitionKey, true)
{
}
}
Expand All @@ -37,14 +46,16 @@ _ = services.AddScoped(_ => new CosmosClient(
clientOptions: new()
{
Serializer = new UniverseSerializer() // This is from Universe.Options
AllowBulkExecution = true // This will tell the underlying code to allow async bulk operations
}
));
```

4. In your Startup.cs / Main method / Program.cs, configure your CosmosDb repository like so:
```csharp
_ = services.AddScoped<IGalaxy<MyModel>, MyRepository>(service => new(
db: service.GetRequiredService<CosmosClient>().GetDatabase("cosmos-database"),
client: service.GetRequiredService<CosmosClient>(),
database: "database-name",
container: "container-name",
partitionKey: "/partitionKey"
));
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<Version>1.3.2</Version>
<Version>1.4.0</Version>
15 changes: 10 additions & 5 deletions code/DarkMatter/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.Azure.Cosmos;
using System.Text.Json.Serialization;
using Microsoft.Azure.Cosmos;
using Universe;
using Universe.Interfaces;
using Universe.Options;
Expand All @@ -14,12 +15,14 @@
CosmosDbPrimaryKey,
clientOptions: new()
{
Serializer = new UniverseSerializer()
Serializer = new UniverseSerializer(),
AllowBulkExecution = true // This will tell the underlying code to allow async bulk operations
}
);

IGalaxy<MyObject> galaxy = new MyRepo(
db: cosmosClient.GetDatabase("<DATABASE NAME>"),
client: cosmosClient,
database: "<DATABASE NAME>",
container: "<CONTAINER NAME>",
partitionKey: "/<PARTITION KEY>"
);
Expand Down Expand Up @@ -63,6 +66,8 @@ class MyObject : ICosmicEntity
public string id { get; set; }
public DateTime AddedOn { get; set; }
public DateTime? ModifiedOn { get; set; }

[JsonIgnore]
public string PartitionKey => Code;

public string Code { get; set; }
Expand All @@ -77,11 +82,11 @@ class MyObject : ICosmicEntity
class MyRepo : Galaxy<MyObject>
{
#if DEBUG
public MyRepo(Database db, string container, string partitionKey) : base(db, container, partitionKey, true)
public MyRepo(CosmosClient client, string database, string container, string partitionKey) : base(client, database, container, partitionKey, true)
{
}
#else
public MyRepo(Database db, string container, string partitionKey) : base(db, container, partitionKey)
public MyRepo(CosmosClient client, string database, string container, string partitionKey) : base(client, database, container, partitionKey)
{
}
#endif
Expand Down
85 changes: 64 additions & 21 deletions code/Universe/Galaxy.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System.Linq;
using System.Net;
using Universe.Options;
using System.Net;
using Universe.Response;

namespace Universe;
Expand All @@ -11,16 +9,19 @@ public abstract class Galaxy<T> : IDisposable, IGalaxy<T> where T : ICosmicEntit
private readonly Container Container;
private bool DisposedValue;

private bool RecordQuery;
private readonly bool RecordQuery;
private readonly bool AllowBulk;

/// <summary></summary>
protected Galaxy(Database db, string container, string partitionKey, bool recordQueries = false)
protected Galaxy(CosmosClient client, string database, string container, string partitionKey, bool recordQueries = false)
{
if (string.IsNullOrWhiteSpace(container) || string.IsNullOrWhiteSpace(partitionKey))
throw new UniverseException("Container name and PartitionKey are required");

RecordQuery = recordQueries;
Container = db.CreateContainerIfNotExistsAsync(container, partitionKey).GetAwaiter().GetResult();
if (client.ClientOptions is not null)
AllowBulk = client.ClientOptions.AllowBulkExecution;
Container = client.GetDatabase(database).CreateContainerIfNotExistsAsync(container, partitionKey).GetAwaiter().GetResult();
}

private static QueryDefinition CreateQuery(IList<Catalyst> catalysts, ColumnOptions? columnOptions = null, IList<Sorting.Option> sorting = null, IList<string> groups = null)
Expand Down Expand Up @@ -108,33 +109,42 @@ private static QueryDefinition CreateQuery(IList<Catalyst> catalysts, ColumnOpti
return (new(response.RequestCharge, null), model.id);
}

async Task<Gravity> IGalaxy<T>.Create(IList<Catalyst> catalysts, T model)
async Task<Gravity> IGalaxy<T>.Create(IList<T> models)
{
QueryDefinition query = CreateQuery(catalysts: catalysts);

using FeedIterator<T> queryResponse = Container.GetItemQueryIterator<T>(query);
if (queryResponse.HasMoreResults)
try
{
FeedResponse<T> next = await queryResponse.ReadNextAsync();
if (next.Count > 0)
throw new UniverseException($"{typeof(T).Name} already exists.");
}
if (!AllowBulk)
throw new UniverseException("Bulk create of documents is not configured properly.");

model.id = Guid.NewGuid().ToString();
model.AddedOn = DateTime.UtcNow;
Gravity gravity = new(0, string.Empty);
List<Task> tasks = new(models.Count);

ItemResponse<T> response = await Container.CreateItemAsync(model, new PartitionKey(model.PartitionKey));
return new(response.RequestCharge, null, RecordQuery ? (query.QueryText, query.GetQueryParameters()) : default);
foreach (T model in models)
{
if (string.IsNullOrWhiteSpace(model.id))
model.id = Guid.NewGuid().ToString();
model.AddedOn = DateTime.UtcNow;

tasks.Add(Container.CreateItemAsync(model, new PartitionKey(model.PartitionKey))
.ContinueWith(response => gravity = new(gravity.RU + response.Result.RequestCharge, string.Empty)));
}

await Task.WhenAll(tasks);
return gravity;
}
catch
{
throw;
}
}

async Task<(Gravity, T)> IGalaxy<T>.Modify(T model)
{
try
{
ItemResponse<T> response = await Container.ReadItemAsync<T>(model.id, new PartitionKey(model.PartitionKey));
model.ModifiedOn = DateTime.UtcNow;

response = await Container.ReplaceItemAsync(model, response.Resource.id, new PartitionKey(response.Resource.PartitionKey));
ItemResponse<T> response = await Container.ReplaceItemAsync(model, model.id, new PartitionKey(model.PartitionKey));
return (new(response.RequestCharge, null), response.Resource);
}
catch (CosmosException ex) when (ex.StatusCode == HttpStatusCode.NotFound)
Expand All @@ -147,6 +157,39 @@ async Task<Gravity> IGalaxy<T>.Create(IList<Catalyst> catalysts, T model)
}
}

async Task<Gravity> IGalaxy<T>.Modify(IList<T> models)
{
try
{
if (!AllowBulk)
throw new UniverseException("Bulk modify of documents is not configured properly.");

Gravity gravity = new(0, string.Empty);
List<Task> tasks = new(models.Count);

foreach (T model in models)
{
model.ModifiedOn = DateTime.UtcNow;

tasks.Add(Container.ReplaceItemAsync(model, model.id, new PartitionKey(model.PartitionKey))
.ContinueWith(response =>
{
if (!response.IsCompletedSuccessfully)
throw new UniverseException(response.Exception.Flatten().InnerException.Message);

gravity = new(gravity.RU + response.Result.RequestCharge, string.Empty);
}));
}

await Task.WhenAll(tasks);
return gravity;
}
catch
{
throw;
}
}

async Task<Gravity> IGalaxy<T>.Remove(string id, string partitionKey)
{
try
Expand Down
9 changes: 7 additions & 2 deletions code/Universe/Interfaces/IGalaxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,20 @@ public interface IGalaxy<T> where T : ICosmicEntity
Task<(Gravity g, string t)> Create(T model);

/// <summary>
/// Create a new model in the database
/// Bulk create new models in the database
/// </summary>
Task<Gravity> Create(IList<Catalyst> catalysts, T model);
Task<Gravity> Create(IList<T> models);

/// <summary>
/// Modify a model in the database
/// </summary>
Task<(Gravity g, T T)> Modify(T model);

/// <summary>
/// Bulk modify models in the database
/// </summary>
Task<Gravity> Modify(IList<T> models);

/// <summary>
/// Remove one model from the database
/// </summary>
Expand Down
6 changes: 3 additions & 3 deletions code/Universe/UniverseQuery.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
<RepositoryType>Git</RepositoryType>
<Authors>Nor Gelera</Authors>
<Product>Universe</Product>
<Version>1.3.2</Version>
<Version>1.4.0</Version>
<PackageReleaseNotes>View release on https://github.com/kuromukira/universe/releases</PackageReleaseNotes>
<AssemblyVersion>1.3.2.0</AssemblyVersion>
<FileVersion>1.3.2.0</FileVersion>
<AssemblyVersion>1.4.0.0</AssemblyVersion>
<FileVersion>1.4.0.0</FileVersion>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
Expand Down
11 changes: 8 additions & 3 deletions code/Universe/UniverseQuery.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit c0b5b44

Please sign in to comment.