Skip to content

Commit

Permalink
Merge branch 'release/universe-1.4.1' into prod
Browse files Browse the repository at this point in the history
  • Loading branch information
kuromukira committed Jan 20, 2023
2 parents c0b5b44 + ca4c750 commit 423cae4
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 40 deletions.
24 changes: 17 additions & 7 deletions code/Universe/Galaxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ protected Galaxy(CosmosClient client, string database, string container, string

private static QueryDefinition CreateQuery(IList<Catalyst> catalysts, ColumnOptions? columnOptions = null, IList<Sorting.Option> sorting = null, IList<string> groups = null)
{
// Validate Catalysts
if (catalysts is not null && catalysts.Any() && catalysts.Any(c => c.RuleViolations().Any()))
{
List<IEnumerable<string>> violationsPerCatalyst = catalysts.Select(c => c.RuleViolations()).ToList();
List<string> violations = violationsPerCatalyst.SelectMany(v => v).ToList().Distinct().ToList();
throw new UniverseException(string.Join(Environment.NewLine, violations));
}

// Column Options Builder
string columnsInQuery = "*";
if (columnOptions is not null)
Expand Down Expand Up @@ -82,19 +90,21 @@ private static QueryDefinition CreateQuery(IList<Catalyst> catalysts, ColumnOpti

// Parameters Builder
QueryDefinition query = new(queryBuilder.ToString());
if (!catalysts.Any()) return query;
{
query = query.WithParameter($"@{catalysts[0].ParameterName()}", catalysts[0].Value);
foreach (Catalyst catalyst in catalysts.Where(p => p.Column != catalysts[0].Column).ToList())
query = query.WithParameter($"@{catalyst.ParameterName()}", catalyst.Value);
}
if (!catalysts.Any())
return query;

query = query.WithParameter($"@{catalysts[0].ParameterName()}", catalysts[0].Value);
foreach (Catalyst catalyst in catalysts.Where(p => p.Column != catalysts[0].Column).ToList())
query = query.WithParameter($"@{catalyst.ParameterName()}", catalyst.Value);

return query;

static string WhereClauseBuilder(Catalyst catalyst) => catalyst.Operator switch
{
Q.Operator.In => $"ARRAY_CONTAINS(c.{catalyst.Column}, @{catalyst.ParameterName()})",
Q.Operator.NotIn => $"NOT ARRAY_CONTAINS(c.{catalyst.Column}, @{catalyst.ParameterName()})",
Q.Operator.Defined => $"IS_DEFINED(c.{catalyst.Column})",
Q.Operator.NotDefined => $"NOT IS_DEFINED(c.{catalyst.Column})",
_ => $"c.{catalyst.Column} {catalyst.Operator.Value()} @{catalyst.ParameterName()}",
};
}
Expand Down Expand Up @@ -363,4 +373,4 @@ public void Dispose()
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
}
52 changes: 36 additions & 16 deletions code/Universe/Options/Parameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,48 @@ namespace Universe.Options.Query;
/// </summary>
/// <param name="Column">Column name</param>
/// <param name="Value">Value for the where clause associated with the Column</param>
/// <param name="Alias">
/// Column name alias excluding the @ symbol for SQL Parameters.
/// If not supplied, this will use the value from <paramref name="Column"/>
/// </param>
/// <param name="Where">Where operator (eg AND / OR)</param>
/// <param name="Operator">Boolean expression operator</param>
public record struct Catalyst(
public readonly record struct Catalyst(
string Column,
object Value,
string Alias = null,
object Value = null,
Q.Where Where = Q.Where.And,
Q.Operator Operator = Q.Operator.Eq);

/// <summary></summary>
public static class CatalystExtension
Q.Operator Operator = Q.Operator.Eq)
{
/// <summary></summary>
public static string ParameterName(this Catalyst catalyst)
/// <summary>Creates a list of rule violations when creating a CosmosDb query catalyst</summary>
public IEnumerable<string> RuleViolations()
{
if (string.IsNullOrWhiteSpace(catalyst.Alias))
return Regex.Replace(catalyst.Column, "[^\\w\\d]", string.Empty);
List<string> violations = new();

// Column name cannot be null or empty
if (string.IsNullOrWhiteSpace(Column))
violations.Add("Column name is required");

// Value should be null if using IS_DEFINED or NOT IS_DEFINED operators
if (Value is not null && Operator is Q.Operator.Defined or Q.Operator.NotDefined)
violations.Add("Value should not be supplied when using the Defined or NotDefined operators");

// Value should have wildcard for Like and Not Like operators
if (Value is not null && Operator is Q.Operator.Like or Q.Operator.NotLike)
{
string value = Value.ToString();
if (string.IsNullOrWhiteSpace(value))
violations.Add("Value is required when using the Like or NotLike operators");
else if (!value.Contains('%'))
violations.Add("Value should contain a wildcard (%) for Like and NotLike operators");
}

return catalyst.Alias;
// Value is required for all other operators
if (Value is null && Operator is not Q.Operator.Defined and not Q.Operator.NotDefined)
violations.Add("Value is required for all operators except Defined and NotDefined");

return violations;
}
}

/// <summary></summary>
public static class CatalystExtension
{
/// <summary></summary>
public static string ParameterName(this Catalyst catalyst) => Regex.Replace(catalyst.Column, "[^\\w\\d]", string.Empty);
}
10 changes: 9 additions & 1 deletion code/Universe/Options/QueryOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,13 @@ public enum Operator
Like,

/// <summary>Not Like</summary>
NotLike
NotLike,

/// <summary>IS_DEFINED</summary>
Defined,

/// <summary>NOT IS_DEFINED</summary>
NotDefined
}
}

Expand Down Expand Up @@ -79,6 +85,8 @@ public static class OperatorExtension
Q.Operator.NotIn => "NOT IN",
Q.Operator.Like => "LIKE",
Q.Operator.NotLike => "NOT LIKE",
Q.Operator.Defined => "IS_DEFINED",
Q.Operator.NotDefined => "NOT IS_DEFINED",
_ => throw new UniverseException("Unrecognized OPERATOR keyword")
};
}
2 changes: 1 addition & 1 deletion code/Universe/UniverseQuery.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
<ItemGroup>
<Folder Include="Exception\" />
<Folder Include="Options\" />
<Folder Include="Responses\" />
<Folder Include="Response\" />
</ItemGroup>

<ItemGroup>
Expand Down
25 changes: 10 additions & 15 deletions code/Universe/UniverseQuery.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 423cae4

Please sign in to comment.