Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions ShopifySharp.Tests/Product_Tests.cs

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions ShopifySharp/Extensions/ObjectExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace ShopifySharp
internal static class ObjectExtensions
{
/// <summary>
/// Converts the object to a dictionary./>
/// Converts the object to a dictionary.
/// </summary>
/// <returns>The object as a <see cref="IDictionary{String, Object}"/>.</returns>
public static IDictionary<string, object> ToDictionary(this object obj)
Expand Down Expand Up @@ -42,4 +42,4 @@ public static IDictionary<string, object> ToDictionary(this object obj)
return output;
}
}
}
}
19 changes: 16 additions & 3 deletions ShopifySharp/Services/Product/ProductService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Threading.Tasks;
using ShopifySharp.Infrastructure;
using ShopifySharp.Lists;
using System.Collections.Generic;

namespace ShopifySharp
{
Expand All @@ -26,7 +27,7 @@ public virtual async Task<int> CountAsync(ProductCountFilter filter = null)
{
return await ExecuteGetAsync<int>("products/count.json", "count", filter);
}

/// <summary>
/// Gets a list of up to 250 of the shop's products.
/// </summary>
Expand Down Expand Up @@ -91,7 +92,7 @@ public virtual async Task<Product> CreateAsync(Product product, ProductCreateOpt
public virtual async Task<Product> UpdateAsync(long productId, Product product)
{
var req = PrepareRequest($"products/{productId}.json");
var content = new JsonContent(new
JsonContent content = new JsonContent(new
{
product = product
});
Expand All @@ -100,6 +101,18 @@ public virtual async Task<Product> UpdateAsync(long productId, Product product)
return response.Result;
}

/// <summary>
/// Updates a <see cref="Product"/>, changing only the fields specified by the <see cref="UpdateBuilder{T}"/>.
/// </summary>
/// <param name="productId">Id of the object being updated.</param>
/// <param name="builder">The fields to update and their values.</param>
/// <returns>The updated <see cref="Product"/>.</returns>
public virtual async Task<Product> UpdateAsync(long productId, UpdateBuilder<Product> builder)
{
var response = await ExecutePutAsync($"products/{productId}.json", "product", builder);
return response;
}

/// <summary>
/// Deletes a product with the given Id.
/// </summary>
Expand Down Expand Up @@ -153,4 +166,4 @@ public virtual async Task<Product> UnpublishAsync(long id)
return response.Result;
}
}
}
}
20 changes: 13 additions & 7 deletions ShopifySharp/Services/ShopifyService.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using ShopifySharp.Filters;
using ShopifySharp.Infrastructure;
using ShopifySharp.Lists;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using ShopifySharp.Infrastructure;
using Newtonsoft.Json;
using System.IO;
using ShopifySharp.Lists;
using ShopifySharp.Filters;

namespace ShopifySharp
{
Expand Down Expand Up @@ -232,6 +232,12 @@ protected async Task<T> ExecutePostAsync<T>(string path, string resultRootElt, o
return await ExecuteWithContentCoreAsync<T>(path, resultRootElt, HttpMethod.Post, jsonContent == null ? null : new JsonContent(jsonContent));
}

protected async Task<T> ExecutePutAsync<T>(string path, string resultRootElt, UpdateBuilder<T> builder) where T : ShopifyObject
{
var content = builder.BuildContent(resultRootElt);
return await ExecuteWithContentCoreAsync<T>(path, resultRootElt, HttpMethod.Put, content);
}

protected async Task<T> ExecutePutAsync<T>(string path, string resultRootElt, object jsonContent = null)
{
return await ExecuteWithContentCoreAsync<T>(path, resultRootElt, HttpMethod.Put, jsonContent == null ? null : new JsonContent(jsonContent));
Expand Down
61 changes: 61 additions & 0 deletions ShopifySharp/Services/UpdateBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using Newtonsoft.Json;
using ShopifySharp.Infrastructure;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace ShopifySharp
{
public class UpdateBuilder<T> where T : ShopifyObject
{
private readonly IDictionary<string, dynamic> _updateFields = new Dictionary<string, dynamic>();
public UpdateBuilder<T> Update<TProperty>(Expression<Func<T, TProperty>> propertySelector, TProperty newvalue)
{
var property = propertySelector.Body as MemberExpression;
if (property == null)
{
throw new ArgumentException($"Selector must be a MemberExpression", nameof(propertySelector));
}
_updateFields[property.Member.Name] = newvalue;
return this;
}

public JsonContent BuildContent(string rootContentElement)
{
if (_updateFields.Count == 0)
{
return null;
}
var propInfos = typeof(T).GetAllDeclaredProperties().Where(prop => _updateFields.Keys.Contains(prop.Name));
IDictionary<string, object> output = new Dictionary<string, object>();

//Inspiration for this code from https://github.com/jaymedavis/stripe.net
foreach (PropertyInfo property in propInfos)
{
object value = _updateFields[property.Name];
string propName = property.Name;

if (property.CustomAttributes.Any(x => x.AttributeType == typeof(JsonPropertyAttribute)))
{
//Get the JsonPropertyAttribute for this property, which will give us its JSON name
JsonPropertyAttribute attribute = property.GetCustomAttributes(typeof(JsonPropertyAttribute), false).Cast<JsonPropertyAttribute>().FirstOrDefault();

propName = attribute != null ? attribute.PropertyName : property.Name;
}

if (value != null && value.GetType().GetTypeInfo().IsEnum)
{
value = ((Enum)value).ToSerializedString();
}

output.Add(propName, value);
}

return new JsonContent(new Dictionary<string, IDictionary<string, dynamic>>(){
{ rootContentElement, output }
});
}
}
}
1 change: 1 addition & 0 deletions ShopifySharp/ShopifySharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<PackageTags>shopify,ecommerce</PackageTags>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="microsoft.extensions.primitives" Version="1.1.0" />
<PackageReference Include="newtonsoft.json" Version="10.0.1" />
</ItemGroup>
Expand Down