Skip to content

Commit

Permalink
Merge
Browse files Browse the repository at this point in the history
  • Loading branch information
vplauzon committed Oct 21, 2023
2 parents 43ae06e + d346005 commit 85ae353
Show file tree
Hide file tree
Showing 7 changed files with 246 additions and 1 deletion.
2 changes: 2 additions & 0 deletions code/DeltaKustoLib/CommandModel/CodeHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace DeltaKustoLib.CommandModel
{
internal static class CodeHelper
{
#region Descendants
public static IEnumerable<TElement> GetAtLeastOneDescendant<TElement>(
this SyntaxElement parent,
string descendantNameForExceptionMessage,
Expand Down Expand Up @@ -95,6 +96,7 @@ public static IReadOnlyList<TElement> GetImmediateDescendants<TElement>(

return descendants;
}
#endregion

#region Extract Children
public static (C1, C2) ExtractChildren<C1, C2>(
Expand Down
4 changes: 4 additions & 0 deletions code/DeltaKustoLib/CommandModel/CommandBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,10 @@ public override int GetHashCode()
case "DeleteTablePolicyStreamingIngestion":
case "DeleteDatabasePolicyStreamingIngestion":
return DeleteStreamingIngestionPolicyCommand.FromCode(commandBlock);
case "AlterTablePolicyRowLevelSecurity":
return AlterRowLevelSecurityPolicyCommand.FromCode(commandBlock);
case "DeleteTablePolicyRowLevelSecurity":
return DeleteRowLevelSecurityPolicyCommand.FromCode(commandBlock);
case "AlterTablePolicyRestrictedViewAccess":
return AlterRestrictedViewPolicyCommand.FromCode(commandBlock);
case "AlterTablesPolicyRestrictedViewAccess":
Expand Down
2 changes: 1 addition & 1 deletion code/DeltaKustoLib/CommandModel/EntityName.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public EntityName(string name)
}
else
{
throw new DeltaException($"Unsuppored character for an entity: '{c}'");
throw new DeltaException($"Unsupported character for an entity: '{c}'");
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
using Kusto.Language.Syntax;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

namespace DeltaKustoLib.CommandModel.Policies
{
/// <summary>
/// Models <see cref="https://learn.microsoft.com/en-us/azure/data-explorer/kusto/management/alter-table-row-level-security-policy-command"/>
/// </summary>
[Command(20100, "Alter Row Level Policies")]
public class AlterRowLevelSecurityPolicyCommand : TableOnlyPolicyCommandBase
{
public bool IsEnabled { get; }

public QuotedText Query { get; }

public override string CommandFriendlyName => ".alter <entity> policy row_level_security";

public override string ScriptPath => $"tables/policies/row_level_security/create/{TableName}";

public AlterRowLevelSecurityPolicyCommand(
EntityName tableName,
bool isEnabled,
QuotedText query)
: base(tableName)
{
IsEnabled = isEnabled;
Query = query;
}

internal static CommandBase FromCode(SyntaxElement rootElement)
{
var tableName = rootElement.GetDescendants<NameReference>().Last();
var isEnabled = rootElement
.GetDescendants<SyntaxElement>(e => e.Kind == SyntaxKind.IdentifierToken)
.Select(e => e.ToString().Trim())
.Where(t => t == "enable" || t == "disable")
.Select(t => new bool?(t == "enable"))
.LastOrDefault();

if (isEnabled == null)
{
throw new DeltaException(
"No 'enable' or 'disable' token found in row level security command");
}

var query = QuotedText.FromLiteral(
rootElement.GetUniqueDescendant<LiteralExpression>(
"Row Level Security",
e => e.NameInParent == "Query"));

return new AlterRowLevelSecurityPolicyCommand(
EntityName.FromCode(tableName.Name),
isEnabled.Value,
query);
}

public override string ToScript(ScriptingContext? context)
{
var builder = new StringBuilder();

builder.Append(".alter table ");
builder.Append(TableName.ToScript());
builder.Append(" policy row_level_security ");
builder.Append(IsEnabled ? "enable" : "disable");
builder.Append(" ");
builder.AppendLine(Query.ToScript());

return builder.ToString();
}

internal static IEnumerable<CommandBase> ComputeDelta(
AlterAutoDeletePolicyCommand? currentCommand,
AlterAutoDeletePolicyCommand? targetCommand)
{
var hasCurrent = currentCommand != null;
var hasTarget = targetCommand != null;

if (hasCurrent && !hasTarget)
{ // No target, we remove the current policy
yield return new DeleteAutoDeletePolicyCommand(currentCommand!.TableName);
}
else if (hasTarget)
{
if (!hasCurrent || !currentCommand!.Equals(targetCommand!))
{ // There is a target and either no current or the current is different
yield return targetCommand!;
}
}
else
{ // Both target and current are null: no delta
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using Kusto.Language.Syntax;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

namespace DeltaKustoLib.CommandModel.Policies
{
/// <summary>
/// Models ??? (unexisting documentation)
/// </summary>
[Command(20000, "Delete Row Level Security Policies")]
public class DeleteRowLevelSecurityPolicyCommand : TableOnlyPolicyCommandBase
{
public override string CommandFriendlyName => ".delete <entity> policy row_level_security";

public override string ScriptPath => "tables/policies/row_level_security/delete";

public DeleteRowLevelSecurityPolicyCommand(EntityName tableName)
: base(tableName)
{
}

internal static CommandBase FromCode(SyntaxElement rootElement)
{
var tableName = rootElement.GetFirstDescendant<NameReference>();

return new DeleteRowLevelSecurityPolicyCommand(EntityName.FromCode(tableName.Name));
}

public override string ToScript(ScriptingContext? context)
{
var builder = new StringBuilder();

builder.Append(".delete table ");
builder.Append(TableName.ToScript());
builder.Append(" policy row_level_security");

return builder.ToString();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using DeltaKustoLib.CommandModel;
using DeltaKustoLib.CommandModel.Policies;
using System;
using System.Linq;
using System.Text.Json;
using Xunit;

namespace DeltaKustoUnitTest.CommandParsing.Policies
{
public class AlterRowLevelSecurityPolicyTest : ParsingTestBase
{
[Fact]
public void SimpleTable()
{
TestRowLevelPolicy("A", "MyFunction");
}

[Fact]
public void FunkyTable()
{
TestRowLevelPolicy("['A- 1']", "MyTable | where TenantId == 42");
}

// Currently not supported by the parser
//[Fact]
//public void DbComposedTableName()
//{
// TestRowLevelPolicy("mydb.mytable", "MyFunction");
//}

// Currently not supported by the parser
//[Fact]
//public void ClusterComposedTableName()
//{
// TestRowLevelPolicy("mycluster.['my db'].mytable", "MyFunction");
//}

private void TestRowLevelPolicy(string tableName, string query)
{
TestRowLevelPolicy(tableName, true, query);
TestRowLevelPolicy(tableName, false, query);
}

private void TestRowLevelPolicy(string tableName, bool isEnabled, string query)
{
var realTableName = tableName.Split('.').Last();
var enableToken = isEnabled ? "enable" : "disable";
var commandText = $@"
.alter table {tableName} policy row_level_security {enableToken} ""{query}""
";
var command = ParseOneCommand(commandText);

Assert.IsType<AlterRowLevelSecurityPolicyCommand>(command);

var realCommand = (AlterRowLevelSecurityPolicyCommand)command;

Assert.Equal(isEnabled, realCommand.IsEnabled);
Assert.Equal(query, realCommand.Query.Text);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using DeltaKustoLib.CommandModel;
using DeltaKustoLib.CommandModel.Policies;
using System;
using System.Linq;
using System.Text.Json;
using Xunit;

namespace DeltaKustoUnitTest.CommandParsing.Policies
{
public class DeleteRowLevelSecurityPolicyTest : ParsingTestBase
{
[Fact]
public void SimpleTable()
{
TestAutoDeletePolicy("A");
}

[Fact]
public void FunkyTable()
{
TestAutoDeletePolicy("A- 1");
}

private void TestAutoDeletePolicy(string tableName)
{
var commandText = new DeleteRowLevelSecurityPolicyCommand(new EntityName(tableName))
.ToScript(null);
var command = ParseOneCommand(commandText);

Assert.IsType<DeleteRowLevelSecurityPolicyCommand>(command);
}
}
}

0 comments on commit 85ae353

Please sign in to comment.