Temporary repo to track my changes on LTS functions app porting
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

327 lines
12 KiB

using Microsoft.Azure.Cosmos;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CDP
{
public class ContactsDB
{
private static Lazy<CosmosClient> lazyClient = new Lazy<CosmosClient>(InitializeCosmosClient);
private static CosmosClient cosmosClient => lazyClient.Value;
private static string DatabaseName = "CDP";
private static string ContainerName = "Contacts";
private static CosmosClient InitializeCosmosClient()
{
// Perform any initialization here
var uri = "https://cdplite.documents.azure.com:443/";
var authKey = "VPbg8RpzyI3XwhC2o0dIUtYFs33ghxORCqZeNAyg8vg4HWUBjM41BUxP0qLFXEvFh6ewQY1uKv52ACDbsEN1AQ==";
return new CosmosClient(uri, authKey);
}
public static async Task<List<ContactRecord>> GetUserContacts(string AppKey, string UserId)
{
var results = new List<ContactRecord>();
Container container = cosmosClient.GetContainer(DatabaseName, ContainerName);
// Fetch the metadata document for the customer ID
var metadataDocumentId = GetMetaDocumentKey(AppKey, UserId);
MetadataDocumentContact metadataDocument = null;
try
{
var metadataDocumentResponse =
await container.ReadItemAsync<MetadataDocumentContact>(metadataDocumentId, new PartitionKey(metadataDocumentId));
metadataDocument = metadataDocumentResponse.Resource;
}
catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
{
}
catch (Exception e)
{
// Helpers.LogIt(e.Message);
}
if (metadataDocument == null)
return results;
// Determine the partition keys within the date range
var partitionKeysInDocument = metadataDocument.PartitionKeys;
// Fetch the audit records for each partition key within the date range
foreach (var partitionKey in partitionKeysInDocument)
{
ItemResponse<ContactsDocument> response = await container.ReadItemAsync<ContactsDocument>(partitionKey, new PartitionKey(partitionKey));
if (response == null)
continue;
ContactsDocument t = response.Resource;
results.AddRange(t.Records);
}
return results;
}
public static async Task<bool> AppendRecord(string appKey, string userId, ContactRecord rec)
{
try
{
var metadataDocument = await GetMetadataDocument(appKey, userId);
if (metadataDocument == null)
return false;
string dayKey = metadataDocument.GetLatestKey(appKey, userId);
ContactsDocument al = await GetContactDocument(dayKey);
if (al == null)
{
al = new ContactsDocument();
al.AppKey = appKey;
al.UserId = userId;
}
al.Records.Add(rec);
await UpdateContactsDocument(al);
return true;
}
catch (Exception e)
{
return false;
}
}
public static async Task<bool> RemoveRecord(string appKey, string userId, string EmailId)
{
Container container = cosmosClient.GetContainer(DatabaseName, ContainerName);
// Fetch the metadata document for the customer ID
var metadataDocumentId = GetMetaDocumentKey(appKey, userId);
MetadataDocumentContact metadataDocument = null;
try
{
var metadataDocumentResponse = await container.ReadItemAsync<MetadataDocumentContact>(metadataDocumentId, new PartitionKey(metadataDocumentId));
metadataDocument = metadataDocumentResponse.Resource;
}
catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
{
}
catch (Exception e)
{
// Helpers.LogIt(e.Message);
}
if (metadataDocument == null)
return false;
// Determine the partition keys within the date range
var partitionKeysInDocument = metadataDocument.PartitionKeys;
// Fetch the audit records for each partition key within the date range
foreach (var partitionKey in partitionKeysInDocument)
{
ItemResponse<ContactsDocument> response = await container.ReadItemAsync<ContactsDocument>(partitionKey, new PartitionKey(partitionKey));
if (response == null)
continue;
ContactsDocument t = response.Resource;
var originalCount = t.Records.Count;
t.Records = t.Records.Where(item => item.Email != EmailId).ToList();
var afterFilterCount = t.Records.Count;
if (originalCount != afterFilterCount)
{
ItemResponse<ContactsDocument> updateResponse = await container.ReplaceItemAsync(
item: t,
id: t.id,
partitionKey: new PartitionKey(partitionKey));
return true;
}
}
return false;
}
public static async Task UpdateContactsDocument(ContactsDocument al)
{
if (al.Records.Count == 0)
return;
List<ContactsDocument> lal = await SplitAuditlog(al);
Container container = cosmosClient.GetContainer(DatabaseName, ContainerName);
foreach (ContactsDocument ial in lal)
{
ItemResponse<ContactsDocument> r = await container.UpsertItemAsync(ial, new PartitionKey(ial.id));
}
await UpdateMetadata(container, lal);
}
static async Task UpdateMetadata(Container container, List<ContactsDocument> lal)
{
bool update = false;
string pKey = GetMetaDocumentKey(lal[0].AppKey, lal[0].UserId);
MetadataDocument md = null;
try
{
ItemResponse<MetadataDocument> response =
await container.ReadItemAsync<MetadataDocument>(pKey, new PartitionKey(pKey));
md = response.Resource;
}
catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
{
md = new MetadataDocument()
{
id = GetMetaDocumentKey(lal[0].AppKey, lal[0].UserId),
PartitionKeys = new List<string>()
};
}
catch (Exception e)
{
// Helpers.LogIt(e.Message);
return;
}
if (md == null)
{
// Helpers.LogIt("Something ugly happened!");
return;
}
foreach (ContactsDocument log in lal)
{
if (md.PartitionKeys.Contains(log.id))
continue;
md.PartitionKeys.Add(log.id);
update = true;
}
if (update)
{
try
{
ItemResponse<MetadataDocument> r = await container.UpsertItemAsync(md, new PartitionKey(pKey));
}
catch (Exception e)
{
// Helpers.LogIt(e.Message);
return;
}
}
}
static async Task<List<ContactsDocument>> SplitAuditlog(ContactsDocument al)
{
List<ContactsDocument> lal = new List<ContactsDocument>();
var sortedRecords = al.Records.OrderBy(record => record.EventTime).ToList();
var currentGroup = new List<ContactRecord>();
var currentGroupSize = 0;
int MaxDocumentSizeInBytes = 2 * 1024 * 1024; // 2MB
int index = al.Index; // start for index passed in
foreach (var record in sortedRecords)
{
var recordSize = record.CalculateRecordSize();
if (currentGroupSize + recordSize > MaxDocumentSizeInBytes)
{
ContactsDocument i = new ContactsDocument();
i.Index = index++;
i.Records = currentGroup;
i.AppKey = al.AppKey;
i.UserId = al.UserId;
lal.Add(i);
currentGroup = new List<ContactRecord>();
currentGroupSize = 0;
}
currentGroup.Add(record);
currentGroupSize += recordSize;
}
if (currentGroup.Any())
{
ContactsDocument i = new ContactsDocument();
i.Index = index++;
i.Records = currentGroup;
i.AppKey = al.AppKey;
i.UserId = al.UserId;
lal.Add(i);
}
return lal;
}
public static async Task<ContactsDocument> GetContactDocument(string key)
{
try
{
Container container = cosmosClient.GetContainer(DatabaseName, ContainerName);
ItemResponse<ContactsDocument> response = await container.ReadItemAsync<ContactsDocument>(key, new PartitionKey(key));
if (response == null)
return null;
ContactsDocument t = response.Resource;
return t;
}
catch (Exception e)
{
return null;
}
}
static async Task<MetadataDocumentContact> GetMetadataDocument(string appKey, string userId)
{
MetadataDocumentContact md = null;
string pKey = GetMetaDocumentKey(appKey, userId);
string id = GetDocumentId(appKey, userId);
PartitionKey partitionKey = new PartitionKeyBuilder()
.Add(pKey)
.Build();
Container container = cosmosClient.GetContainer(DatabaseName, ContainerName);
try
{
ItemResponse<MetadataDocumentContact> response =
await container.ReadItemAsync<MetadataDocumentContact>(pKey, partitionKey);
md = response.Resource;
}
catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
{
md = new MetadataDocumentContact()
{
id = id,
PartitionKeys = new List<string>()
};
}
catch (Exception e)
{
// Helpers.LogIt(e.Message);
return null;
}
if (md == null)
{
// Helpers.LogIt("Something ugly happened!");
return null;
}
return md;
}
static string GetMetaDocumentKey(string appKey, string userId)
{
return $"{appKey}-{userId}-meta";
}
static string GetDocumentId(string appKey, string userId)
{
return $"{appKey}-{userId}";
}
}
}