Skip to content

Commit

Permalink
Add support for Fields parameter in Search and Admin APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
const-cloudinary committed Dec 1, 2023
1 parent 82c7ae1 commit 3740ddd
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 34 deletions.
16 changes: 16 additions & 0 deletions CloudinaryDotNet.IntegrationTests/AdminApi/BrowseResourcesTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,22 @@ public void TestListResourcesByTag()
AssertListResourcesByTagResult(result);
}

[Test, RetryWithDelay]
public void TestListResourcesFields()
{
var result = m_cloudinary.ListResources(new ListResourcesParams
{
Fields = new[] { "tags", "secure_url"}
});

Assert.GreaterOrEqual(result.Resources.Count(), 1, result.Error?.Message);


Assert.IsNotEmpty(result.Resources[0].AssetId);
Assert.IsNotNull(result.Resources[0].SecureUrl);
Assert.IsNull(result.Resources[0].Url);
}

[Test, RetryWithDelay]
public async Task TestListResourcesByTagAsync()
{
Expand Down
83 changes: 50 additions & 33 deletions CloudinaryDotNet.IntegrationTests/SearchApi/SearchApiTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,34 @@ class SearchApiTest : IntegrationTestBase
private string m_singleResourcePublicId;
private string[] m_publicIdsSorted;
private Dictionary<string, string> m_assetIds = new Dictionary<string, string>();
private const int INDEXING_WAIT_TIME = 5000;
private const int IndexingWaitTime = 5000;

private const string SORT_FIELD = "public_id";
private const string SORT_DIRECTION_ASC = "asc";
private const string SortField = "public_id";
private const string SortDirectionAsc = "asc";

private const string AGG_FIELD_VALUE = "resource_type";
private const string METADATA_FIELD_NAME = "image_metadata";
private const string STRUCTURED_METADATA_FIELD_NAME = "metadata";
private const string TAGS_FIELD_NAME = "tags";
private const string CONTEXT_FIELD_NAME = "context";
private const string IMAGE_ANALYSIS_FIELD_NAME = "image_analysis";
private const string AggFieldValue = "resource_type";
private const string MetadataFieldName = "image_metadata";
private const string StructuredMetadataFieldName = "metadata";
private const string TagsFieldName = "tags";
private const string ContextFieldName = "context";
private const string ImageAnalysisFieldName = "image_analysis";
private const string SecureUrlFieldName = "secure_url";
private const string UrlFieldName = "url";

private const int FIRST_PAGE_SIZE = 1;
private const int SECOND_PAGE_SIZE = 2;
private const int RESOURCES_COUNT = 3;
private const int FirstPageSize = 1;
private const int SecondPageSize = 2;
private const int ResourcesCount = 3;

[OneTimeSetUp]
public void InitSearchTests()
{
m_searchTag = GetMethodTag();
m_expressionTag = $"tags:{m_searchTag}";
m_publicIdsSorted = new string[RESOURCES_COUNT];
m_publicIdsSorted = new string[ResourcesCount];

CreateMetadataField("metadata_search");

for (var i = 0; i < RESOURCES_COUNT; i++)
for (var i = 0; i < ResourcesCount; i++)
{
var publicId = GetUniquePublicId();
var uploadParams = new ImageUploadParams
Expand All @@ -62,7 +64,7 @@ public void InitSearchTests()

Array.Sort(m_publicIdsSorted);
m_expressionPublicId = $"public_id: {m_publicIdsSorted[0]}";
Thread.Sleep(INDEXING_WAIT_TIME);
Thread.Sleep(IndexingWaitTime);
}

[TestCase("asset_id=")]
Expand All @@ -81,7 +83,7 @@ public void TestSearchApiFindResourcesByTag()
var result = m_cloudinary.Search().Expression(m_expressionTag).Execute();

Assert.NotNull(result.Resources, result.Error?.Message);
Assert.AreEqual(RESOURCES_COUNT, result.Resources.Count);
Assert.AreEqual(ResourcesCount, result.Resources.Count);
}

[Test, RetryWithDelay]
Expand All @@ -94,21 +96,21 @@ public void TestSearchResourceByPublicId()
[Test, RetryWithDelay]
public void TestPaginateResourcesLimitedByTagAndOrderedByAscendingPublicId()
{
var result = m_cloudinary.Search().MaxResults(FIRST_PAGE_SIZE)
.Expression(m_expressionTag).SortBy(SORT_FIELD, SORT_DIRECTION_ASC).Execute();
var result = m_cloudinary.Search().MaxResults(FirstPageSize)
.Expression(m_expressionTag).SortBy(SortField, SortDirectionAsc).Execute();

Assert.NotNull(result.Resources, result.Error?.Message);
Assert.AreEqual(FIRST_PAGE_SIZE, result.Resources.Count);
Assert.AreEqual(RESOURCES_COUNT, result.TotalCount);
Assert.AreEqual(FirstPageSize, result.Resources.Count);
Assert.AreEqual(ResourcesCount, result.TotalCount);
Assert.AreEqual(m_publicIdsSorted.First(), result.Resources.First().PublicId);

result = m_cloudinary.Search().MaxResults(SECOND_PAGE_SIZE)
.Expression(m_expressionTag).SortBy(SORT_FIELD, SORT_DIRECTION_ASC)
result = m_cloudinary.Search().MaxResults(SecondPageSize)
.Expression(m_expressionTag).SortBy(SortField, SortDirectionAsc)
.NextCursor(result.NextCursor).Execute();

Assert.NotNull(result.Resources, result.Error?.Message);
Assert.AreEqual(SECOND_PAGE_SIZE, result.Resources.Count);
Assert.AreEqual(RESOURCES_COUNT, result.TotalCount);
Assert.AreEqual(SecondPageSize, result.Resources.Count);
Assert.AreEqual(ResourcesCount, result.TotalCount);
Assert.AreEqual(m_publicIdsSorted.Last(), result.Resources.Last().PublicId);

Assert.True(string.IsNullOrEmpty(result.Resources[0].Folder));
Expand All @@ -134,31 +136,46 @@ public void TestPaginateResourcesLimitedByTagAndOrderedByAscendingPublicId()
public void TestSearchAggregate()
{
var result = m_cloudinary.Search()
.Expression(m_expressionTag).Aggregate(AGG_FIELD_VALUE).Execute();
.Expression(m_expressionTag).Aggregate(AggFieldValue).Execute();

AssertSupportsAggregation(result);

Assert.NotNull(result.Resources, result.Error?.Message);
Assert.AreEqual(RESOURCES_COUNT, result.Resources.Count);
Assert.AreEqual(ResourcesCount, result.Resources.Count);
Assert.IsNotEmpty(result.Aggregations);
}

[Test, RetryWithDelay]
public void TestSearchWithField()
{
var result = m_cloudinary.Search().MaxResults(FIRST_PAGE_SIZE)
.Expression(m_expressionTag).WithField(METADATA_FIELD_NAME).Execute();
var result = m_cloudinary.Search().MaxResults(FirstPageSize)
.Expression(m_expressionTag).WithField(MetadataFieldName).Execute();

Assert.NotNull(result.Resources, result.Error?.Message);
Assert.AreEqual(FIRST_PAGE_SIZE, result.Resources.Count);
Assert.AreEqual(FirstPageSize, result.Resources.Count);
Assert.IsNotEmpty(result.Resources.First().ImageMetadata);
}

[Test, RetryWithDelay]
public void TestSearchFields()
{
var result = m_cloudinary.Search().MaxResults(FirstPageSize)
.Expression(m_expressionTag).Fields(MetadataFieldName)
.Fields(new List<string>{SecureUrlFieldName, SortField}).Execute();

Assert.NotNull(result.Resources, result.Error?.Message);
Assert.AreEqual(FirstPageSize, result.Resources.Count);
Assert.IsNotEmpty(result.Resources.First().PublicId);
Assert.IsNotEmpty(result.Resources.First().ImageMetadata);
Assert.IsNotEmpty(result.Resources.First().SecureUrl);
Assert.IsNull(result.Resources.First().Url);
}

[Test, RetryWithDelay]
public void TestRootResponseFieldsAreParsed()
{
var result = m_cloudinary.Search().MaxResults(FIRST_PAGE_SIZE)
.Expression(m_expressionTag).Aggregate(AGG_FIELD_VALUE).Execute();
var result = m_cloudinary.Search().MaxResults(FirstPageSize)
.Expression(m_expressionTag).Aggregate(AggFieldValue).Execute();

AssertSupportsAggregation(result);

Expand All @@ -173,8 +190,8 @@ public void TestRootResponseFieldsAreParsed()
public void TestResourceResponseFieldsAreParsed()
{
var result = m_cloudinary.Search().Expression($"public_id: {m_singleResourcePublicId}")
.WithField(METADATA_FIELD_NAME).WithField(IMAGE_ANALYSIS_FIELD_NAME)
.WithField(CONTEXT_FIELD_NAME).WithField(TAGS_FIELD_NAME).WithField(STRUCTURED_METADATA_FIELD_NAME)
.WithField(MetadataFieldName).WithField(ImageAnalysisFieldName)
.WithField(ContextFieldName).WithField(TagsFieldName).WithField(StructuredMetadataFieldName)
.Execute();
var foundResource = result.Resources.First();

Expand Down
10 changes: 10 additions & 0 deletions CloudinaryDotNet/Actions/AssetsManagement/ListResourcesParams.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ public class ListResourcesParams : BaseParams
/// </summary>
public bool Metadata { get; set; }

/// <summary>
/// Gets or sets a list of fields to return in the response.
/// </summary>
public string[] Fields { get; set; }

/// <summary>
/// Gets or sets when a listing request has more results to return than <see cref="ListResourcesParams.MaxResults"/>,
/// the <see cref="NextCursor"/> value is returned as part of the response. You can then specify this value as
Expand Down Expand Up @@ -87,6 +92,11 @@ public override SortedDictionary<string, object> ToParamsDictionary()
AddParam(dict, "tags", Tags);
AddParam(dict, "moderations", Moderations);
AddParam(dict, "context", Context);
if (Fields != null)
{
AddParam(dict, "fields", string.Join(",", Fields));
}

AddParam(dict, "direction", Direction);
AddParam(dict, "type", Type);
AddParam(dict, "metadata", Metadata);
Expand Down
31 changes: 30 additions & 1 deletion CloudinaryDotNet/Search/SearchBaseFluent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public abstract class SearchBaseFluent<T>
private List<Dictionary<string, object>> sortByParam;
private List<string> aggregateParam;
private List<string> withFieldParam;
private List<string> fieldsParam;
private Dictionary<string, object> searchParams;

/// <summary>
Expand All @@ -32,6 +33,7 @@ public SearchBaseFluent(ApiShared api)
sortByParam = new List<Dictionary<string, object>>();
aggregateParam = new List<string>();
withFieldParam = new List<string>();
fieldsParam = new List<string>();
}

/// <summary>
Expand Down Expand Up @@ -103,6 +105,28 @@ public T WithField(string field)
return (T)this;
}

/// <summary>
/// The name of the asset attribute to keep for each asset in the response.
/// </summary>
/// <param name="field">The name of field.</param>
/// <returns>The search provider with additional asset attribute defined.</returns>
public T Fields(string field)
{
fieldsParam.Add(field);
return (T)this;
}

/// <summary>
/// The list of the names of the asset attributes to keep for each asset in the response.
/// </summary>
/// <param name="fields">The names of fields.</param>
/// <returns>The search provider with additional asset attribute defined.</returns>
public T Fields(IEnumerable<string> fields)
{
fieldsParam.AddRange(fields);
return (T)this;
}

/// <summary>
/// Set sort parameter. If this parameter is not provided then the results are sorted by descending
/// creation date. Valid sort directions are 'asc' or 'desc'.
Expand All @@ -124,13 +148,18 @@ public T SortBy(string field, string dir)
/// <returns>Search parameters as dictionary.</returns>
public Dictionary<string, object> ToQuery()
{
Dictionary<string, object> queryParams = new Dictionary<string, object>(searchParams);
var queryParams = new Dictionary<string, object>(searchParams);

if (withFieldParam.Count > 0)
{
queryParams.Add("with_field", withFieldParam.Distinct());
}

if (fieldsParam.Count > 0)
{
queryParams.Add("fields", fieldsParam.Distinct());
}

if (sortByParam.Count > 0)
{
queryParams.Add("sort_by", sortByParam.GroupBy(d => d.Keys.First()).Select(l => l.Last()));
Expand Down

0 comments on commit 3740ddd

Please sign in to comment.