diff --git a/src/libraries/Microsoft.PowerFx.Connectors/Internal/Wrappers/Extensions.cs b/src/libraries/Microsoft.PowerFx.Connectors/Internal/Wrappers/Extensions.cs index 37f37bee32..b8a9b0f1cb 100644 --- a/src/libraries/Microsoft.PowerFx.Connectors/Internal/Wrappers/Extensions.cs +++ b/src/libraries/Microsoft.PowerFx.Connectors/Internal/Wrappers/Extensions.cs @@ -2,9 +2,12 @@ // Licensed under the MIT license. using System; +using System.Collections.Generic; +using System.Linq; using System.Text.Json; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; +using Microsoft.PowerFx.Core.Functions.Delegation; namespace Microsoft.PowerFx.Connectors { @@ -27,5 +30,15 @@ public static IOpenApiExtension ToIOpenApiExtension(this JsonElement je) _ => throw new NotImplementedException() }; } + + public static IEnumerable ToStr(this IEnumerable ops) + { + if (ops == null) + { + return null; + } + + return ops.Select(op => op.ToString().ToLowerInvariant()); + } } } diff --git a/src/libraries/Microsoft.PowerFx.Connectors/Public/CDPPocos/CapabilitiesPoco.cs b/src/libraries/Microsoft.PowerFx.Connectors/Public/CDPPocos/CapabilitiesPoco.cs new file mode 100644 index 0000000000..430d04f88f --- /dev/null +++ b/src/libraries/Microsoft.PowerFx.Connectors/Public/CDPPocos/CapabilitiesPoco.cs @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using Microsoft.PowerFx.Core.Functions.Delegation; + +namespace Microsoft.PowerFx.Connectors +{ + public class CapabilitiesPoco + { + [JsonPropertyName("sortRestrictions")] + public Sort SortRestrictions { get; set; } + + [JsonPropertyName("filterRestrictions")] + public Filter FilterRestrictions { get; set; } + + [JsonPropertyName("isOnlyServerPagable")] + public bool IsOnlyServerPagable { get; set; } + + // "top", "skiptoken" + [JsonPropertyName("serverPagingOptions")] + public string[] ServerPagingOptions { get; set; } + + // and,or,eq, etc... + // DelegationOperator + [JsonPropertyName("filterFunctionSupport")] + public string[] FilterFunctionSupport { get; set; } + + public CapabilitiesPoco SetOps(IEnumerable ops) + { + this.FilterFunctionSupport = ops.ToStr().ToArray(); + return this; + } + + public IEnumerable FilterFunctionSupportOps() => Utilities.ToDelegationOp(FilterFunctionSupport); + + // 3 + [JsonPropertyName("odataVersion")] + public int OdataVersion { get; set; } + } + + public class Filter + { + [JsonPropertyName("filterable")] + public bool Filterable { get; set; } + + [JsonPropertyName("nonFilterableProperties")] + public string[] NonFilterableProperties { get; set; } + } + + public class Sort + { + [JsonPropertyName("sortable")] + public bool Sortable { get; set; } + + [JsonPropertyName("unsortableProperties")] + public string[] UnsortableProperties { get; set; } + } +} diff --git a/src/libraries/Microsoft.PowerFx.Connectors/Public/CDPPocos/ColumnCapabilitiesPoco.cs b/src/libraries/Microsoft.PowerFx.Connectors/Public/CDPPocos/ColumnCapabilitiesPoco.cs new file mode 100644 index 0000000000..7640a14683 --- /dev/null +++ b/src/libraries/Microsoft.PowerFx.Connectors/Public/CDPPocos/ColumnCapabilitiesPoco.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using Microsoft.PowerFx.Core.Functions.Delegation; + +namespace Microsoft.PowerFx.Connectors +{ + public class ColumnCapabilitiesPoco + { + [JsonPropertyName("filterFunctions")] + public string[] FilterFunctions { get; set; } + + // Strong-typing + public IEnumerable FilterFunctionOps() => + Utilities.ToDelegationOp(FilterFunctions); + + public static ColumnCapabilitiesPoco New(IEnumerable ops) + { + return new ColumnCapabilitiesPoco + { + FilterFunctions = ops.ToStr().ToArray() + }; + } + } +} diff --git a/src/libraries/Microsoft.PowerFx.Connectors/Public/CDPPocos/GetTablePoco.cs b/src/libraries/Microsoft.PowerFx.Connectors/Public/CDPPocos/GetTablePoco.cs new file mode 100644 index 0000000000..da51cd265e --- /dev/null +++ b/src/libraries/Microsoft.PowerFx.Connectors/Public/CDPPocos/GetTablePoco.cs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.Json.Serialization; + +namespace Microsoft.PowerFx.Connectors +{ + public class GetTablePoco + { + [JsonPropertyName("name")] + public string Name { get; set; } + + [JsonPropertyName("x-ms-permission")] + public string Permissions { get; set; } // read-write + + // $$$ Fill in rest of stuff here... + [JsonPropertyName("x-ms-capabilities")] + public CapabilitiesPoco Capabilities { get; set; } + + [JsonPropertyName("schema")] + public TableSchemaPoco Schema { get; set; } + } +} diff --git a/src/libraries/Microsoft.PowerFx.Connectors/Public/CDPPocos/TableSchemaPoco.cs b/src/libraries/Microsoft.PowerFx.Connectors/Public/CDPPocos/TableSchemaPoco.cs new file mode 100644 index 0000000000..5941135c3a --- /dev/null +++ b/src/libraries/Microsoft.PowerFx.Connectors/Public/CDPPocos/TableSchemaPoco.cs @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.Json.Serialization; + +namespace Microsoft.PowerFx.Connectors +{ + public class TableSchemaPoco + { + [JsonPropertyName("type")] + public string Type { get; set; } = "array"; + + [JsonPropertyName("items")] + public ItemsPoco Items { get; set; } + } + + public class ItemsPoco + { + [JsonPropertyName("type")] + public string Type { get; set; } = "object"; + + // need required flag. + [JsonPropertyName("properties")] + public Dictionary Properties { get; set; } + } + + public class ColumnInfoPoco + { + [JsonPropertyName("title")] + public string Title { get; set; } + + [JsonPropertyName("description")] + public string Description { get; set; } + + [JsonPropertyName("type")] + public string Type { get; set; } // $$$ "integer", "string", + + // What sorting capabilities? + // "asc,desc" + [JsonPropertyName("x-ms-sort")] + public string Sort { get; set; } + + // What filter capabilities? + [JsonPropertyName("x-ms-capabilities")] + public ColumnCapabilitiesPoco Capabilities { get; set; } + } +} diff --git a/src/libraries/Microsoft.PowerFx.Connectors/Public/ConnectorType.cs b/src/libraries/Microsoft.PowerFx.Connectors/Public/ConnectorType.cs index 84b59af319..2b9d57bab7 100644 --- a/src/libraries/Microsoft.PowerFx.Connectors/Public/ConnectorType.cs +++ b/src/libraries/Microsoft.PowerFx.Connectors/Public/ConnectorType.cs @@ -273,11 +273,14 @@ internal ConnectorType(JsonElement schema, string tableName, SymbolTable optionS DisplayName = displayName; FieldMetadata = fieldMetadata; - foreach (ConnectorType field in Fields.Where(f => f.Capabilities != null)) + if (serviceCapabilities != null) { - serviceCapabilities.AddColumnCapability(field.Name, field.Capabilities); + foreach (ConnectorType field in Fields.Where(f => f.Capabilities != null)) + { + serviceCapabilities.AddColumnCapability(field.Name, field.Capabilities); + } } - + FormulaType = new CdpRecordType(this, resolver, ServiceCapabilities.ToDelegationInfo(serviceCapabilities, name, isTableReadOnly, this, datasetName), FieldMetadata); } diff --git a/src/libraries/Microsoft.PowerFx.Connectors/Tabular/CdpTableResolver.cs b/src/libraries/Microsoft.PowerFx.Connectors/Tabular/CdpTableResolver.cs index cfbc09c7df..35a9682028 100644 --- a/src/libraries/Microsoft.PowerFx.Connectors/Tabular/CdpTableResolver.cs +++ b/src/libraries/Microsoft.PowerFx.Connectors/Tabular/CdpTableResolver.cs @@ -59,8 +59,11 @@ public async Task ResolveTableAsync(string logicalName, Cancellat } string dataset = _doubleEncoding ? CdpServiceBase.DoubleEncode(_tabularTable.DatasetName) : CdpServiceBase.SingleEncode(_tabularTable.DatasetName); + + // URI to fetch table metadata. string uri = (_uriPrefix ?? string.Empty) + (UseV2(_uriPrefix) ? "/v2" : string.Empty) + $"/$metadata.json/datasets/{dataset}/tables/{CdpServiceBase.DoubleEncode(logicalName)}?api-version=2015-09-01"; + // $$$ we need to return POCO string text = await CdpServiceBase.GetObject(_httpClient, $"Get table metadata", uri, null, cancellationToken, Logger).ConfigureAwait(false); if (string.IsNullOrWhiteSpace(text)) diff --git a/src/libraries/Microsoft.PowerFx.Connectors/Tabular/Services/CdpServiceBase.cs b/src/libraries/Microsoft.PowerFx.Connectors/Tabular/Services/CdpServiceBase.cs index bd16e07c15..8c0482b635 100644 --- a/src/libraries/Microsoft.PowerFx.Connectors/Tabular/Services/CdpServiceBase.cs +++ b/src/libraries/Microsoft.PowerFx.Connectors/Tabular/Services/CdpServiceBase.cs @@ -25,12 +25,6 @@ protected internal static async Task GetObject(HttpClient httpClient, stri string result = await GetObject(httpClient, message, uri, content, cancellationToken, logger, $"{callingMethod}<{typeof(T).Name}>").ConfigureAwait(false); T res = string.IsNullOrWhiteSpace(result) ? null : JsonSerializer.Deserialize(result); - - if (res is ISupportsPostProcessing postProcessing) - { - postProcessing.PostProcess(); - } - return res; } diff --git a/src/libraries/Microsoft.PowerFx.Connectors/Tabular/Services/CdpTable.cs b/src/libraries/Microsoft.PowerFx.Connectors/Tabular/Services/CdpTable.cs index 9733c925ab..09e88dfceb 100644 --- a/src/libraries/Microsoft.PowerFx.Connectors/Tabular/Services/CdpTable.cs +++ b/src/libraries/Microsoft.PowerFx.Connectors/Tabular/Services/CdpTable.cs @@ -41,7 +41,7 @@ public class CdpTable : CdpService internal ConnectorType TabularTableDescriptor; - internal IReadOnlyCollection Tables; + internal IEnumerable Tables; private string _uriPrefix; @@ -56,7 +56,7 @@ public class CdpTable : CdpService public override ConnectorSettings ConnectorSettings => _connectorSettings; - internal CdpTable(string dataset, string table, IReadOnlyCollection tables, ConnectorSettings connectorSettings, CDPMetadataItem fieldMetadata = null) + internal CdpTable(string dataset, string table, IEnumerable tables, ConnectorSettings connectorSettings, CDPMetadataItem fieldMetadata = null) { DatasetName = dataset ?? throw new ArgumentNullException(nameof(dataset)); TableName = table ?? throw new ArgumentNullException(nameof(table)); @@ -65,7 +65,7 @@ internal CdpTable(string dataset, string table, IReadOnlyCollection ta _fieldMetadata = fieldMetadata; } - internal CdpTable(string dataset, string table, DatasetMetadata datasetMetadata, IReadOnlyCollection tables, ConnectorSettings connectorSettings, CDPMetadataItem fieldMetadata) + internal CdpTable(string dataset, string table, DatasetMetadata datasetMetadata, IEnumerable tables, ConnectorSettings connectorSettings, CDPMetadataItem fieldMetadata) : this(dataset, table, tables, connectorSettings, fieldMetadata) { DatasetMetadata = datasetMetadata; diff --git a/src/libraries/Microsoft.PowerFx.Connectors/Tabular/Services/InternalObjects.cs b/src/libraries/Microsoft.PowerFx.Connectors/Tabular/Services/InternalObjects.cs index 8c312b9652..c7a3f95ca4 100644 --- a/src/libraries/Microsoft.PowerFx.Connectors/Tabular/Services/InternalObjects.cs +++ b/src/libraries/Microsoft.PowerFx.Connectors/Tabular/Services/InternalObjects.cs @@ -9,25 +9,32 @@ namespace Microsoft.PowerFx.Connectors { // Used by ConnectorDataSource.GetTablesAsync - internal class GetTables : ISupportsPostProcessing + public class GetTables { [JsonPropertyName("@metadata")] - public List Metadata { get; set; } + internal List Metadata { get; set; } - [JsonPropertyName("value")] - public List Value { get; set; } + private IEnumerable _value; - public void PostProcess() + [JsonPropertyName("value")] + public IEnumerable Value { - Value = Value.Select(rt => new RawTable() { Name = rt.Name, DisplayName = rt.DisplayName.Split('.').Last().Replace("[", string.Empty).Replace("]", string.Empty) }).ToList(); + get => _value; + set => + _value = value? + .Select(rt => new RawTable + { + Name = rt.Name, + DisplayName = rt.DisplayName + .Split('.') + .Last() + .Replace("[", string.Empty) + .Replace("]", string.Empty) + }) + .ToList(); } } - internal interface ISupportsPostProcessing - { - void PostProcess(); - } - internal class CDPMetadataItem { [JsonPropertyName("name")] @@ -68,12 +75,17 @@ public class CDPSensitivityLabelInfo public bool IsParent { get; set; } } - internal class RawTable + public class RawTable { - // Logical Name + /// + /// Logical name of the table. + /// [JsonPropertyName("Name")] public string Name { get; set; } + /// + /// Display name of the table. + /// [JsonPropertyName("DisplayName")] public string DisplayName { get; set; } diff --git a/src/libraries/Microsoft.PowerFx.Connectors/Utilities.cs b/src/libraries/Microsoft.PowerFx.Connectors/Utilities.cs new file mode 100644 index 0000000000..9d097fd451 --- /dev/null +++ b/src/libraries/Microsoft.PowerFx.Connectors/Utilities.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.PowerFx.Core.Functions.Delegation; + +namespace Microsoft.PowerFx.Connectors +{ + internal class Utilities + { + public static IEnumerable ToDelegationOp(IEnumerable filterFunctionList) + { + if (filterFunctionList == null) + { + return null; + } + + List list = new List(); + + foreach (string str in filterFunctionList) + { + if (Enum.TryParse(str, true, out DelegationOperator op)) + { + list.Add(op); + } + } + + return list; + } + } +}