Skip to content

Commit

Permalink
Add "supportsJoin" capability (#2786)
Browse files Browse the repository at this point in the history
  • Loading branch information
LucGenetier authored Dec 18, 2024
1 parent b2d9f8a commit c3acfe9
Show file tree
Hide file tree
Showing 6 changed files with 232 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ internal static class CapabilityConstants
public const string SPIsChoice = "IsChoice";
public const string SPQueryName = "OdataQueryName";
public const string SupportsRecordPermission = "supportsRecordPermission";
public const string SupportsJoin = "supportsJoin";
public const string UngroupableProperties = "ungroupableProperties";
public const string UnsortableProperties = "unsortableProperties";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,15 @@ internal sealed class ServiceCapabilities : IColumnsCapabilities
[JsonPropertyName(CapabilityConstants.SupportsRecordPermission)]
public readonly bool SupportsRecordPermission;

[JsonInclude]
[JsonPropertyName(CapabilityConstants.SupportsJoin)]
public readonly bool SupportsJoinFunction;

public const int CurrentODataVersion = 4;

public ServiceCapabilities(SortRestriction sortRestriction, FilterRestriction filterRestriction, SelectionRestriction selectionRestriction, GroupRestriction groupRestriction, IEnumerable<string> filterFunctions,
IEnumerable<string> filterSupportedFunctions, PagingCapabilities pagingCapabilities, bool recordPermissionCapabilities, int oDataVersion = CurrentODataVersion, bool supportsDataverseOffline = false)
IEnumerable<string> filterSupportedFunctions, PagingCapabilities pagingCapabilities, bool recordPermissionCapabilities, int oDataVersion = CurrentODataVersion, bool supportsDataverseOffline = false,
bool supportsJoinFunction = false)
{
Contracts.AssertValueOrNull(sortRestriction);
Contracts.AssertValueOrNull(filterRestriction);
Expand All @@ -120,6 +125,7 @@ public ServiceCapabilities(SortRestriction sortRestriction, FilterRestriction fi
_columnsCapabilities = null;
ODataVersion = oDataVersion;
SupportsRecordPermission = recordPermissionCapabilities;
SupportsJoinFunction = supportsJoinFunction;
}

public static TableDelegationInfo ToDelegationInfo(ServiceCapabilities serviceCapabilities, string tableName, bool isReadOnly, ConnectorType connectorType, string datasetName)
Expand Down Expand Up @@ -189,7 +195,10 @@ public static TableDelegationInfo ToDelegationInfo(ServiceCapabilities serviceCa
SupportsRecordPermission = serviceCapabilities?.SupportsRecordPermission ?? false,
ColumnsCapabilities = columnCapabilities,
ColumnsWithRelationships = columnWithRelationships,
PrimaryKeyNames = primaryKeyNames
PrimaryKeyNames = primaryKeyNames,
#pragma warning disable CS0618 // Type or member is obsolete
SupportsJoinFunction = serviceCapabilities?.SupportsJoinFunction ?? false
#pragma warning restore CS0618 // Type or member is obsolete
};
}

Expand Down Expand Up @@ -233,14 +242,15 @@ public static ServiceCapabilities ParseTableCapabilities(IDictionary<string, IOp
string[] filterSupportedFunctions = ParseFilterSupportedFunctions(capabilitiesMetaData);
PagingCapabilities pagingCapabilities = ParsePagingCapabilities(capabilitiesMetaData);
bool recordPermissionCapabilities = ParseRecordPermissionCapabilities(capabilitiesMetaData);
bool supportsJoinFunction = ParseSupportsJoinCapabilities(capabilitiesMetaData);
int oDataVersion = capabilitiesMetaData.GetInt(CapabilityConstants.ODataversionOption, defaultValue: CurrentODataVersion);

if (oDataVersion > CurrentODataVersion || oDataVersion < 3)
{
throw new PowerFxConnectorException("Table capabilities specifies an unsupported oDataVersion");
}

return new ServiceCapabilities(sortRestriction, filterRestriction, selectionRestriction, groupRestriction, filterFunctions, filterSupportedFunctions, pagingCapabilities, recordPermissionCapabilities, oDataVersion);
return new ServiceCapabilities(sortRestriction, filterRestriction, selectionRestriction, groupRestriction, filterFunctions, filterSupportedFunctions, pagingCapabilities, recordPermissionCapabilities, oDataVersion, supportsJoinFunction: supportsJoinFunction);
}

private static FilterRestriction ParseFilterRestriction(IDictionary<string, IOpenApiAny> capabilitiesMetaData)
Expand Down Expand Up @@ -296,5 +306,10 @@ private static bool ParseRecordPermissionCapabilities(IDictionary<string, IOpenA
{
return capabilitiesMetaData.GetBool(CapabilityConstants.SupportsRecordPermission);
}

private static bool ParseSupportsJoinCapabilities(IDictionary<string, IOpenApiAny> capabilitiesMetaData)
{
return capabilitiesMetaData.GetBool(CapabilityConstants.SupportsJoin);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
Expand Down Expand Up @@ -37,6 +38,9 @@ public abstract class TableDelegationInfo
// Supports per record permission
internal bool SupportsRecordPermission { get; init; }

[Obsolete("preview")]
public bool SupportsJoinFunction { get; init; }

// Logical name of table
public string TableName { get; init; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Responses\SQL GetDatasetsMetadata.json" />
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Responses\SQL GetTables.json" />
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Responses\SQL GetSchema ProductModel.json" />
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Responses\SQL GetSchema Products v2.json" />
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Responses\SQL GetSchema Products.json" />
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Responses\SQL GetTables SampleDB.json" />
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Responses\SQL GetRelationships SampleDB.json" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,46 @@ public async Task SQL_CdpTabular_GetTables2()
Assert.Equal("ProductID", string.Join("|", GetPrimaryKeyNames(sqlTable.RecordType)));
}

[Fact]
public async Task SQL_CdpTabular_JoinCapabilityTest()
{
using var testConnector = new LoggingTestServer(null /* no swagger */, _output);
var config = new PowerFxConfig(Features.PowerFxV1);
var engine = new RecalcEngine(config);

ConsoleLogger logger = new ConsoleLogger(_output);
using var httpClient = new HttpClient(testConnector);
string connectionId = "2cc03a388d38465fba53f05cd2c76181";
string jwt = "eyJ0eXAiOiJKSuA...";
using var client = new PowerPlatformConnectorClient("dac64a92-df6a-ee6e-a6a2-be41a923e371.15.common.tip1002.azure-apihub.net", "dac64a92-df6a-ee6e-a6a2-be41a923e371", connectionId, () => jwt, httpClient) { SessionId = "8e67ebdc-d402-455a-b33a-304820832383" };

string realTableName = "Product";

CdpDataSource cds = new CdpDataSource("default,default");

testConnector.SetResponseFromFiles(@"Responses\SQL GetDatasetsMetadata.json", @"Responses\SQL GetTables SampleDB.json");
IEnumerable<CdpTable> tables = await cds.GetTablesAsync(client, $"/apim/sql/{connectionId}", CancellationToken.None, logger);

CdpTable table = tables.First(t => t.DisplayName == realTableName);

testConnector.SetResponseFromFiles(@"Responses\SQL GetSchema Products v2.json");
await table.InitAsync(client, $"/apim/sql/{connectionId}", CancellationToken.None, logger);
Assert.True(table.IsInitialized);

CdpTableValue sqlTable = table.GetTableValue();
Assert.True(sqlTable._tabularService.IsInitialized);
Assert.True(sqlTable.IsDelegable);

HashSet<IExternalTabularDataSource> ads = sqlTable.Type._type.AssociatedDataSources;
Assert.NotNull(ads);
Assert.Single(ads);

DataSourceInfo dsi = Assert.IsType<DataSourceInfo>(ads.First());
#pragma warning disable CS0618 // Type or member is obsolete
Assert.True(dsi.DelegationInfo.SupportsJoinFunction);
#pragma warning restore CS0618 // Type or member is obsolete
}

[Fact]
public async Task SAP_CDP()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
{
"name": "[SalesLT].[Product]",
"title": "[SalesLT].[Product]",
"x-ms-permission": "read-write",
"x-ms-capabilities": {
"sortRestrictions": { "sortable": true },
"filterRestrictions": { "filterable": true },
"selectRestrictions": { "selectable": true },
"filterFunctionSupport": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "add", "sub", "mul", "div", "mod", "negate", "now", "not", "and", "or", "day", "month", "year", "hour", "minute", "second", "date", "time", "totaloffsetminutes", "totalseconds", "round", "floor", "ceiling", "contains", "startswith", "endswith", "length", "indexof", "replace", "substring", "substringof", "tolower", "toupper", "trim", "concat", "sum", "min", "max", "average", "countdistinct", "null" ],
"supportsJoin": true
},
"schema": {
"type": "array",
"items": {
"type": "object",
"required": [ "Name", "ProductNumber", "StandardCost", "ListPrice", "SellStartDate", "rowguid", "ModifiedDate" ],
"properties": {
"ProductID": {
"title": "ProductID",
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "add", "sub", "mul", "div", "mod", "negate", "sum", "average" ] },
"type": "integer",
"format": "int32",
"minimum": -2147483648,
"maximum": 2147483647,
"x-ms-keyOrder": 1,
"x-ms-keyType": "primary",
"x-ms-permission": "read-only",
"x-ms-sort": "none"
},
"Name": {
"title": "Name",
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "contains", "startswith", "endswith", "length", "indexof", "replace", "substring", "substringof", "tolower", "toupper", "trim", "concat" ] },
"type": "string",
"maxLength": 50,
"x-ms-permission": "read-write",
"x-ms-sort": "none"
},
"ProductNumber": {
"title": "ProductNumber",
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "contains", "startswith", "endswith", "length", "indexof", "replace", "substring", "substringof", "tolower", "toupper", "trim", "concat" ] },
"type": "string",
"maxLength": 25,
"x-ms-permission": "read-write",
"x-ms-sort": "none"
},
"Color": {
"title": "Color",
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "contains", "startswith", "endswith", "length", "indexof", "replace", "substring", "substringof", "tolower", "toupper", "trim", "concat" ] },
"type": "string",
"maxLength": 15,
"x-ms-permission": "read-write",
"x-ms-sort": "none"
},
"StandardCost": {
"title": "StandardCost",
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "add", "sub", "mul", "div", "round", "floor", "ceiling", "negate", "sum", "average" ] },
"type": "number",
"format": "currency",
"x-ms-permission": "read-write",
"x-ms-sort": "none"
},
"ListPrice": {
"title": "ListPrice",
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "add", "sub", "mul", "div", "round", "floor", "ceiling", "negate", "sum", "average" ] },
"type": "number",
"format": "currency",
"x-ms-permission": "read-write",
"x-ms-sort": "none"
},
"Size": {
"title": "Size",
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "contains", "startswith", "endswith", "length", "indexof", "replace", "substring", "substringof", "tolower", "toupper", "trim", "concat" ] },
"type": "string",
"maxLength": 5,
"x-ms-permission": "read-write",
"x-ms-sort": "none"
},
"Weight": {
"title": "Weight",
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "add", "sub", "mul", "div", "round", "floor", "ceiling", "negate", "sum", "average" ] },
"type": "number",
"format": "double",
"minimum": -79228162514264337593543950335.0,
"maximum": 79228162514264337593543950335.0,
"x-ms-permission": "read-write",
"x-ms-sort": "none"
},
"ProductCategoryID": {
"title": "ProductCategoryID",
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "add", "sub", "mul", "div", "mod", "negate", "sum", "average" ] },
"type": "integer",
"format": "int32",
"minimum": -2147483648,
"maximum": 2147483647,
"x-ms-permission": "read-write",
"x-ms-sort": "none"
},
"ProductModelID": {
"title": "ProductModelID",
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "add", "sub", "mul", "div", "mod", "negate", "sum", "average" ] },
"type": "integer",
"format": "int32",
"minimum": -2147483648,
"maximum": 2147483647,
"x-ms-permission": "read-write",
"x-ms-sort": "none"
},
"SellStartDate": {
"title": "SellStartDate",
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "day", "month", "year", "hour", "minute", "second", "date", "time" ] },
"type": "string",
"format": "date-no-tz",
"x-ms-permission": "read-write",
"x-ms-sort": "none"
},
"SellEndDate": {
"title": "SellEndDate",
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "day", "month", "year", "hour", "minute", "second", "date", "time" ] },
"type": "string",
"format": "date-no-tz",
"x-ms-permission": "read-write",
"x-ms-sort": "none"
},
"DiscontinuedDate": {
"title": "DiscontinuedDate",
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "day", "month", "year", "hour", "minute", "second", "date", "time" ] },
"type": "string",
"format": "date-no-tz",
"x-ms-permission": "read-write",
"x-ms-sort": "none"
},
"ThumbNailPhoto": {
"title": "ThumbNailPhoto",
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct" ] },
"type": "string",
"format": "byte",
"x-ms-permission": "read-write",
"x-ms-sort": "none"
},
"ThumbnailPhotoFileName": {
"title": "ThumbnailPhotoFileName",
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "contains", "startswith", "endswith", "length", "indexof", "replace", "substring", "substringof", "tolower", "toupper", "trim", "concat" ] },
"type": "string",
"maxLength": 50,
"x-ms-permission": "read-write",
"x-ms-sort": "none"
},
"rowguid": {
"title": "rowguid",
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "contains", "startswith", "endswith", "length", "indexof", "replace", "substring", "substringof", "tolower", "toupper", "trim", "concat" ] },
"type": "string",
"format": "guid",
"x-ms-permission": "read-write",
"x-ms-sort": "none"
},
"ModifiedDate": {
"title": "ModifiedDate",
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "day", "month", "year", "hour", "minute", "second", "date", "time" ] },
"type": "string",
"format": "date-no-tz",
"x-ms-permission": "read-write",
"x-ms-sort": "none"
}
}
},
"x-ms-permission": "read-write"
}
}

0 comments on commit c3acfe9

Please sign in to comment.