Skip to content

Commit

Permalink
Properties reset (#37)
Browse files Browse the repository at this point in the history
* Added ability to reset properties back to null
* Updated check to allow contacts / deals / companies with all properties reset
* Updated formatting
  • Loading branch information
agnerh authored Sep 13, 2021
1 parent 8ede25c commit 2102a9a
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 106 deletions.
31 changes: 15 additions & 16 deletions src/HubSpot/Companies/HubSpotCompanyConnector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,26 +47,25 @@ public HubSpotCompanyConnector(IHubSpotClient client, ICompanyTypeManager typeMa
throw new ArgumentNullException(nameof(company));
}

var modifiedProperties = (from property in _typeManager.GetModifiedProperties(company)
select new ValuedPropertyV2(property.name, property.value)).ToArray();
var customProperties = (from property in _typeManager.GetPropertyData(company)
select new ValuedPropertyV2(property.PropertyName, property.Value?.ToString()))
.ToArray();

if (modifiedProperties.Any())
if (customProperties.All(cp => string.IsNullOrEmpty(cp.Value)) && IsNew())
{
if (IsNew())
{
var createdCompany = await _client.Companies.CreateAsync(modifiedProperties).ConfigureAwait(false);
var newCompany = await _client.Companies.GetByIdAsync(createdCompany.Id).ConfigureAwait(false);
return _typeManager.ConvertTo<TCompany>(newCompany);
}
else
{
await _client.Companies.UpdateAsync(company.Id, modifiedProperties).ConfigureAwait(false);
var modifiedCompany = await _client.Companies.GetByIdAsync(company.Id).ConfigureAwait(false);
return _typeManager.ConvertTo<TCompany>(modifiedCompany);
}
return company;
}

return company;
if (IsNew())
{
var createdCompany = await _client.Companies.CreateAsync(customProperties).ConfigureAwait(false);
var newCompany = await _client.Companies.GetByIdAsync(createdCompany.Id).ConfigureAwait(false);
return _typeManager.ConvertTo<TCompany>(newCompany);
}

await _client.Companies.UpdateAsync(company.Id, customProperties).ConfigureAwait(false);
var modifiedCompany = await _client.Companies.GetByIdAsync(company.Id).ConfigureAwait(false);
return _typeManager.ConvertTo<TCompany>(modifiedCompany);

bool IsNew()
{
Expand Down
29 changes: 14 additions & 15 deletions src/HubSpot/Contacts/HubSpotContactConnector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,25 +50,24 @@ public async Task<TContact> SaveAsync<TContact>(TContact contact)
throw new ArgumentNullException(nameof(contact));
}

var modifiedProperties = (from property in _typeManager.GetModifiedProperties(contact)
select new ValuedProperty(property.name, property.value)).ToArray();
var customProperties = (from property in _typeManager.GetPropertyData(contact)
select new ValuedProperty(property.PropertyName, property.Value?.ToString()))
.ToArray();

if (modifiedProperties.Any())
if (customProperties.All(cp => string.IsNullOrEmpty(cp.Value)) && IsNewContact())
{
if (IsNewContact())
{
var newContact = await _client.Contacts.CreateAsync(modifiedProperties);
return _typeManager.ConvertTo<TContact>(newContact);
}
else
{
await _client.Contacts.UpdateByIdAsync(contact.Id, modifiedProperties);
var newContact = await GetAsync<TContact>(SelectContact.ById(contact.Id));
return newContact;
}
return contact;
}

if (IsNewContact())
{
var newContact = await _client.Contacts.CreateAsync(customProperties);
return _typeManager.ConvertTo<TContact>(newContact);
}

return contact;
await _client.Contacts.UpdateByIdAsync(contact.Id, customProperties);
var modifiedContact = await GetAsync<TContact>(SelectContact.ById(contact.Id));
return modifiedContact;

bool IsNewContact()
{
Expand Down
40 changes: 20 additions & 20 deletions src/HubSpot/Deals/HubSpotDealConnector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,36 +46,36 @@ public async Task<TDeal> SaveAsync<TDeal>(TDeal deal)
throw new ArgumentNullException(nameof(deal));
}

var modifiedProperties = (from property in _typeManager.GetModifiedProperties(deal)
select new ValuedPropertyV2(property.name, property.value)).ToArray();
var customProperties = (from property in _typeManager.GetPropertyData(deal)
select new ValuedPropertyV2(property.PropertyName, property.Value?.ToString()))
.ToArray();

var hasProperties = !customProperties.All(cp => string.IsNullOrEmpty(cp.Value));

var modifiedAssociations = _typeManager.GetModifiedAssociations(deal).ToNestedLookup(o => o.type, o => o.operation, o => o.id);

if (modifiedProperties.Any() || modifiedAssociations.Any())
if (!hasProperties && IsNew() && !modifiedAssociations.Any())
{
if (IsNew())
{
var newDeal = await _client.Deals.CreateAsync(deal.AssociatedContactIds, deal.AssociatedCompanyIds, modifiedProperties).ConfigureAwait(false);
return deal;
}

return _typeManager.ConvertTo<TDeal>(newDeal);
}
else
{
await _client.Deals.UpdateAsync(deal.Id, modifiedProperties).ConfigureAwait(false);
if (IsNew())
{
var newDeal = await _client.Deals.CreateAsync(deal.AssociatedContactIds, deal.AssociatedCompanyIds, customProperties).ConfigureAwait(false);
return _typeManager.ConvertTo<TDeal>(newDeal);
}

await _client.Deals.AssociateContactsAsync(deal.Id, modifiedAssociations.GetValues(AssociationType.Contact, Operation.Added)).ConfigureAwait(false);
await _client.Deals.AssociateCompaniesAsync(deal.Id, modifiedAssociations.GetValues(AssociationType.Company, Operation.Added)).ConfigureAwait(false);
await _client.Deals.UpdateAsync(deal.Id, customProperties).ConfigureAwait(false);

await _client.Deals.RemoveAssociationToContactsAsync(deal.Id, modifiedAssociations.GetValues(AssociationType.Contact, Operation.Removed)).ConfigureAwait(false);
await _client.Deals.RemoveAssociationToCompaniesAsync(deal.Id, modifiedAssociations.GetValues(AssociationType.Company, Operation.Removed)).ConfigureAwait(false);
await _client.Deals.AssociateContactsAsync(deal.Id, modifiedAssociations.GetValues(AssociationType.Contact, Operation.Added)).ConfigureAwait(false);
await _client.Deals.AssociateCompaniesAsync(deal.Id, modifiedAssociations.GetValues(AssociationType.Company, Operation.Added)).ConfigureAwait(false);

var updatedDeal = await GetAsync<TDeal>(SelectDeal.ById(deal.Id)).ConfigureAwait(false);
await _client.Deals.RemoveAssociationToContactsAsync(deal.Id, modifiedAssociations.GetValues(AssociationType.Contact, Operation.Removed)).ConfigureAwait(false);
await _client.Deals.RemoveAssociationToCompaniesAsync(deal.Id, modifiedAssociations.GetValues(AssociationType.Company, Operation.Removed)).ConfigureAwait(false);

return updatedDeal;
}
}
var updatedDeal = await GetAsync<TDeal>(SelectDeal.ById(deal.Id)).ConfigureAwait(false);

return deal;
return updatedDeal;

bool IsNew()
{
Expand Down
2 changes: 1 addition & 1 deletion src/HubSpot/Internal/ITypeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ T ConvertTo<T>(THubSpot item)
IReadOnlyList<CustomPropertyInfo> GetCustomProperties<T>(Func<CustomPropertyAttribute, bool> filter)
where T : class, TEntity, new();

IReadOnlyList<(string name, string value)> GetModifiedProperties<T>(T item)
IReadOnlyList<PropertyData> GetPropertyData<T>(T item)
where T : class, TEntity, new();
}

Expand Down
48 changes: 14 additions & 34 deletions src/HubSpot/Internal/TypeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,29 +114,27 @@ where filter(attribute)

protected abstract IReadOnlyList<KeyValuePair<string, object>> GetDefaultProperties(THubSpot item);

public IReadOnlyList<(string name, string value)> GetModifiedProperties<T>(T item)
public IReadOnlyList<PropertyData> GetPropertyData<T>(T item)
where T : class, TEntity, new()
{
var properties = GetCustomProperties<T>(TypeManager.ModifiableProperties);

var data = from property in properties
let value = property.ValueAccessor(item)
select new PropertyData
{
PropertyName = property.FieldName,
Value = value
};
var propertyData = from property in properties
let value = property.ValueAccessor(item)
select new PropertyData
{
PropertyName = property.FieldName,
Value = value
};

var modifiedProperties = GetModifiedProperties(data, item);
var converted = ConvertPropertyValues(propertyData);

return modifiedProperties.ToArray();
return converted.ToList().AsReadOnly();
}

private IEnumerable<(string name, string value)> GetModifiedProperties(IEnumerable<PropertyData> currentValues, IHubSpotEntity entity)
private IEnumerable<PropertyData> ConvertPropertyValues(IEnumerable<PropertyData> properties)
{
var oldValues = entity.Properties;

foreach (var property in currentValues)
foreach (var property in properties)
{
if (!property.Value.IsDefaultValue())
{
Expand All @@ -150,29 +148,11 @@ where filter(attribute)
throw new Exception($"{converter.GetType()} could not convert {property.Value ?? "<null>"} for {property.PropertyName}");
}

if (!oldValues.TryGetValue(property.PropertyName, out var value))
{
yield return (property.PropertyName, newValue);
}
else
{
if (!converter.TryConvertFrom(value, out var oldValue))
{
throw new Exception($"{converter.GetType()} could not convert {value ?? "<null>"} for {property.PropertyName}");
}

if (!string.Equals(newValue, oldValue))
{
yield return (property.PropertyName, newValue);
}
}
yield return new PropertyData(property.PropertyName, newValue);
}
else
{
if (oldValues.TryGetValue(property.PropertyName, out var value) && value != null)
{
yield return (property.PropertyName, null);
}
yield return new PropertyData(property.PropertyName, null);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions tests/Tests.HubSpot/Contacts/HubSpotContactConnectorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,14 @@ public void SaveAsync_requires_a_contact()
}

[Test, CustomAutoData]
public async Task SaveAsync_persists_a_new_contact(TestContact contact, (string, string)[] properties)
public async Task SaveAsync_persists_a_new_contact(TestContact contact, PropertyData[] properties)
{
contact.Id = 0;
contact.Created = default;

var toCreate = CreateFromContact(contact);

mockTypeManager.Setup(p => p.GetModifiedProperties(It.IsAny<TestContact>())).Returns(properties);
mockTypeManager.Setup(p => p.GetPropertyData(It.IsAny<TestContact>())).Returns(properties);

mockContactClient.Setup(p => p.CreateAsync(It.IsAny<IReadOnlyList<ValuedProperty>>())).ReturnsAsync(toCreate);

Expand Down
20 changes: 2 additions & 18 deletions tests/Tests.Integrations/Contacts/HubSpotContactConnectorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -278,22 +278,6 @@ public async Task Empty_contact_should_not_be_persisted()
Assert.That(newContact, Is.SameAs(contact));
}

[Test, ContactAutoData]
public async Task Unmodified_contact_should_not_be_persisted(TestContact contact)
{
SetPropertyDictionary(contact);

var sut = CreateSystemUnderTest();

var newContact = await sut.SaveAsync(contact);

mockClient.Verify(p => p.CreateAsync(It.IsAny<IReadOnlyList<ValuedProperty>>()), Times.Never);

mockClient.Verify(p => p.UpdateByIdAsync(It.IsAny<long>(), It.IsAny<IReadOnlyList<ValuedProperty>>()), Times.Never);

Assert.That(newContact, Is.SameAs(contact));
}

[Test, ContactAutoData]
public async Task Reference_property_reset_to_default_value_should_be_persisted(TestContact contact)
{
Expand All @@ -309,7 +293,7 @@ public async Task Reference_property_reset_to_default_value_should_be_persisted(

var newContact = await sut.SaveAsync(contact);

mockClient.Verify(p => p.UpdateByIdAsync(contact.Id, It.Is<IReadOnlyList<ValuedProperty>>(c => c.Single().Property == "customProperty")), Times.Once);
mockClient.Verify(p => p.UpdateByIdAsync(contact.Id, It.IsAny<IReadOnlyList<ValuedProperty>>()), Times.Once);

Assert.That(newContact.CustomProperty, Is.Null);
}
Expand All @@ -329,7 +313,7 @@ public async Task Value_property_reset_to_default_value_should_be_persisted(Test

var newContact = await sut.SaveAsync(contact);

mockClient.Verify(p => p.UpdateByIdAsync(contact.Id, It.Is<IReadOnlyList<ValuedProperty>>(c => c.Single().Property == "associatedcompanyid")), Times.Once);
mockClient.Verify(p => p.UpdateByIdAsync(contact.Id, It.IsAny<IReadOnlyList<ValuedProperty>>()), Times.Once);

Assert.That(newContact.AssociatedCompanyId, Is.EqualTo(0));
}
Expand Down

0 comments on commit 2102a9a

Please sign in to comment.