Skip to content

Commit

Permalink
Filter query string serialization updates
Browse files Browse the repository at this point in the history
  • Loading branch information
ustims committed May 29, 2023
1 parent c7e2a33 commit 2cfdccf
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 23 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
branches: [ "main" ]

env:
PACKAGE_VERSION: 0.1.1
PACKAGE_VERSION: 0.1.2

jobs:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ public static class FilterConnectorQueryStringExtensions
{
public static string Serialize(this FilterConnector filterConnector)
{
return $"{filterConnector.Logic}+{filterConnector.Filter.Serialize()}";
return $"{filterConnector.Logic}{ProjectionQueryQueryStringExtensions.FILTER_LOGIC_JOIN_CHARACTER}{filterConnector.Filter.Serialize()}";
}

public static FilterConnector Deserialize(string serialized)
{
var separator = "+";
var separator = $"{ProjectionQueryQueryStringExtensions.FILTER_LOGIC_JOIN_CHARACTER}";

var logicEnd = serialized.IndexOf(separator, StringComparison.Ordinal);

Expand Down
37 changes: 23 additions & 14 deletions CloudFabric.Projections/Queries/FilterQueryStringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,40 +64,47 @@ public static string Serialize(this Filter filter, bool useShortcuts = true)

if (filter.Filters != null && filter.Filters.Count > 0)
{
filtersSerialized = string.Join(".", filter.Filters.Select(f => f.Serialize()));
filtersSerialized = string.Join(
ProjectionQueryQueryStringExtensions.FILTER_NESTED_FILTERS_JOIN_CHARACTER,
filter.Filters.Select(f => f.Serialize())
);
}

const char PROPS_JOIN = ProjectionQueryQueryStringExtensions.FILTER_PROPERTIES_JOIN_CHARACTER;

return $"{(string.IsNullOrEmpty(filter.PropertyName) ? "*" : SanitizeValue(filter.PropertyName))}" +
$"|{(string.IsNullOrEmpty(filter.Operator) ? "*" : filter.Operator)}" +
$"|{System.Net.WebUtility.UrlEncode(valueSerialized)}" +
$"|{(filter.Visible ? 'T' : 'F')}" +
$"|{System.Net.WebUtility.UrlEncode(filter.Tag)}" +
$"|{filtersSerialized}";
$"{PROPS_JOIN}{(string.IsNullOrEmpty(filter.Operator) ? "*" : filter.Operator)}" +
$"{PROPS_JOIN}{System.Net.WebUtility.UrlEncode(valueSerialized)}" +
$"{PROPS_JOIN}{(filter.Visible.ToString().ToLower())}" +
$"{PROPS_JOIN}{System.Net.WebUtility.UrlEncode(filter.Tag)}" +
$"{PROPS_JOIN}{filtersSerialized}";
}

public static Filter Deserialize(string f)
{
if (f.IndexOf("|", StringComparison.Ordinal) < 0)
const char PROPS_JOIN = ProjectionQueryQueryStringExtensions.FILTER_PROPERTIES_JOIN_CHARACTER;

if (f.IndexOf(PROPS_JOIN, StringComparison.Ordinal) < 0)
{
if (FacetFilterShortcuts.ContainsKey(f))
{
return FacetFilterShortcuts[f];
}
}

var propertyNameEnd = f.IndexOf("|", StringComparison.Ordinal);
var propertyNameEnd = f.IndexOf($"{PROPS_JOIN}", StringComparison.Ordinal);
var propertyName = DesanitizeValue(f.Substring(0, propertyNameEnd));

var operatorEnd = f.IndexOf("|", propertyNameEnd + 1, StringComparison.Ordinal);
var operatorEnd = f.IndexOf($"{PROPS_JOIN}", propertyNameEnd + 1, StringComparison.Ordinal);
var operatorValue = f.Substring(propertyNameEnd + 1, operatorEnd - propertyNameEnd - 1);

var valueEnd = f.IndexOf("|", operatorEnd + 1, StringComparison.Ordinal);
var valueEnd = f.IndexOf($"{PROPS_JOIN}", operatorEnd + 1, StringComparison.Ordinal);
var value = f.Substring(operatorEnd + 1, valueEnd - operatorEnd - 1);

var visibleEnd = f.IndexOf("|", valueEnd + 1, StringComparison.Ordinal);
var visible = f.Substring(valueEnd + 1, visibleEnd - valueEnd - 1) == "T";
var visibleEnd = f.IndexOf($"{PROPS_JOIN}", valueEnd + 1, StringComparison.Ordinal);
var visible = f.Substring(valueEnd + 1, visibleEnd - valueEnd - 1) == "true";

var tagEnd = f.IndexOf("|", visibleEnd + 1, StringComparison.Ordinal);
var tagEnd = f.IndexOf($"{PROPS_JOIN}", visibleEnd + 1, StringComparison.Ordinal);
var tag = f.Substring(visibleEnd + 1, tagEnd - visibleEnd - 1);

tag = System.Net.WebUtility.UrlDecode(tag);
Expand All @@ -123,7 +130,9 @@ public static Filter Deserialize(string f)

var filters = new List<FilterConnector>();

var filtersSerializedList = f.Substring(tagEnd + 1).Split('.');
var filtersSerializedList = f.Substring(tagEnd + 1)
.Split(ProjectionQueryQueryStringExtensions.FILTER_NESTED_FILTERS_JOIN_CHARACTER);

if (filtersSerializedList.Length > 0)
{
filters = filtersSerializedList
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,33 @@ namespace CloudFabric.Projections.Queries;

public static class ProjectionQueryQueryStringExtensions
{
/// <summary>
/// Top-level filters are joined using this character
/// </summary>
public const char FILTERS_JOIN_CHARACTER = '!';

/// <summary>
/// Individual filter properties are joined using this character.
/// Example: my_boolean_property|eq|true
/// </summary>
public const char FILTER_PROPERTIES_JOIN_CHARACTER = '|';

/// <summary>
/// Character used to join filter connector and the filter it's attached to.
///
/// Example: AND+my_boolean_property|eq|true
/// </summary>
public const char FILTER_LOGIC_JOIN_CHARACTER = '$';

/// <summary>
/// Character used to join array of nested filters.
///
/// Example: my_boolean_property|eq|true|and$my_int_property|gt|100000000.or$my_string_property|eq|'yo'
/// ^- main property filter ^- start of nester filter array ^- second filter is joined with .
/// (joined using | like all props)
/// </summary>
public const char FILTER_NESTED_FILTERS_JOIN_CHARACTER = '.';

public static string SerializeToQueryString(
this ProjectionQuery projectionQuery,
string? searchText = null,
Expand Down Expand Up @@ -39,7 +66,7 @@ public static string SerializeFiltersToQueryString(this ProjectionQuery projecti

if (filtersSerialized.Count > 0)
{
return "sv1_" + string.Join("!", filtersSerialized);
return "sv1_" + string.Join(FILTERS_JOIN_CHARACTER, filtersSerialized);
}
else
{
Expand All @@ -55,22 +82,23 @@ public static void DeserializeFiltersQueryString(this ProjectionQuery projection
}

var searchVersionPlaceholder = "sv";
var version = "";
var version = "1";

if (filters.IndexOf(searchVersionPlaceholder) == 0)
{
var end = filters.IndexOf("_", searchVersionPlaceholder.Length);
var versionLength = end - searchVersionPlaceholder.Length;

version = filters.Substring(searchVersionPlaceholder.Length, versionLength);

// remove version from filters string
filters = filters.Substring(filters.IndexOf("_") + 1);
}

switch (version)
{
case "1":
// remove version from filters string
filters = filters.Substring(filters.IndexOf("_") + 1);
var filtersList = filters.Split('!').Where(f => f.Length > 0).ToList();
var filtersList = filters.Split(FILTERS_JOIN_CHARACTER).Where(f => f.Length > 0).ToList();

if (filtersList.Count > 0)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ private static string ConstructOneConditionFilter(Queries.Filter filter)
{
filterValue = filterValue.ToLower();
}

switch (filter.Operator)
{
case FilterOperator.ArrayContains:
Expand Down

0 comments on commit 2cfdccf

Please sign in to comment.