Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Postgres Function support added #2270

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Config/DatabasePrimitives/DatabaseObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public SourceDefinition SourceDefinition
EntitySourceType.Table => ((DatabaseTable)this).TableDefinition,
EntitySourceType.View => ((DatabaseView)this).ViewDefinition,
EntitySourceType.StoredProcedure => ((DatabaseStoredProcedure)this).StoredProcedureDefinition,
EntitySourceType.Function => ((DatabaseStoredProcedure)this).StoredProcedureDefinition,
_ => throw new Exception(
message: $"Unsupported EntitySourceType. It can either be Table,View, or Stored Procedure.")
};
Expand Down
3 changes: 2 additions & 1 deletion src/Config/ObjectModel/EntitySourceType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ public enum EntitySourceType
{
Table,
View,
[EnumMember(Value = "stored-procedure")] StoredProcedure
[EnumMember(Value = "stored-procedure")] StoredProcedure,
Function
}
6 changes: 4 additions & 2 deletions src/Core/Resolvers/BaseQueryStructure.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public virtual string MakeDbConnectionParam(object? value, string? paramName = n
string encodedParamName = GetEncodedParamName(Counter.Next());
if (!string.IsNullOrEmpty(paramName))
{
Parameters.Add(encodedParamName,
Parameters.Add(paramName,
new(value,
dbType: GetUnderlyingSourceDefinition().GetDbTypeForParam(paramName),
sqlDbType: GetUnderlyingSourceDefinition().GetSqlDbTypeForParam(paramName)));
Expand All @@ -130,7 +130,9 @@ public virtual string MakeDbConnectionParam(object? value, string? paramName = n
Parameters.Add(encodedParamName, new(value));
}

return encodedParamName;
return paramName == null ? encodedParamName : $"{PARAM_NAME_PREFIX}{paramName}";


}

/// <summary>
Expand Down
85 changes: 80 additions & 5 deletions src/Core/Resolvers/PostgresQueryBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,59 @@ public string Build(SqlDeleteStructure structure)
/// </summary>
public string Build(SqlExecuteStructure structure)
{
throw new NotImplementedException();
return $"SELECT * FROM {QuoteIdentifier(structure.DatabaseObject.SchemaName)}.{QuoteIdentifier(structure.DatabaseObject.Name)}({BuildProcedureParameterList(structure.ProcedureParameters)})";
}
private string BuildProcedureParameterList(Dictionary<string, object> parameters)
{
if (parameters == null || parameters.Count == 0)
{
return "";
}

List<string> parameterList = new();
foreach (KeyValuePair<string, object> param in parameters)
{
parameterList.Add($"{QuoteIdentifier(param.Key)} := {FormatParameterValue(param.Value)}");
}

return string.Join(", ", parameterList);
}

#pragma warning disable CA1822 // Mark members as static
private string? FormatParameterValue(object value)
#pragma warning restore CA1822 // Mark members as static
{
if (value == null)
{
return "NULL";
}

if (value is string || value is char)
{
if (value == null)
{
value = string.Empty;
}
// Handle string values, escaping single quotes
#pragma warning disable CS8602 // Dereference of a possibly null reference.
return $"{value.ToString().Replace("'", "''")}";
#pragma warning restore CS8602 // Dereference of a possibly null reference.
}

if (value is bool)
{
// Handle boolean values
return (bool)value ? "TRUE" : "FALSE";
}

if (value is DateTime)
{
// Handle DateTime values
return $"'{((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss")}'";
}

// Handle numeric and other types
return value == null ? string.Empty : value.ToString();
}

public string Build(SqlUpsertQueryStructure structure)
Expand Down Expand Up @@ -218,13 +270,36 @@ private string MakeSelectColumns(SqlQueryStructure structure)

return string.Join(", ", builtColumns);
}

/// <inheritdoc/>
public string BuildStoredProcedureResultDetailsQuery(string databaseObjectName)
public string BuildStoredProcedureResultDetailsQuery(string procedureName)
{
throw new NotImplementedException();
// This query retrieves the details of the result set for a given stored procedure

string query = $@"
SELECT
p.parameter_name AS name,
p.data_type AS system_type_name,
CASE
WHEN p.parameter_mode = 'IN' THEN FALSE
ELSE TRUE
END AS is_nullable
FROM
information_schema.parameters p
JOIN
information_schema.routines r
ON p.specific_name = r.specific_name
WHERE
r.routine_schema = 'public'
and p.parameter_mode = 'OUT'
AND r.routine_name = '{procedureName}'
ORDER BY
p.ordinal_position";



return query;
}


/// <inheritdoc/>
public string BuildQueryToGetReadOnlyColumns(string schemaParamName, string tableParamName)
{
Expand Down
119 changes: 116 additions & 3 deletions src/Core/Services/MetadataProviders/MySqlMetadataProvider.cs
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.Collections;
using System.Data;
using Azure.DataApiBuilder.Config.DatabasePrimitives;
using Azure.DataApiBuilder.Core.Configurations;
Expand Down Expand Up @@ -128,12 +129,124 @@ protected override DatabaseTable GenerateDbTable(string schemaName, string table
}

/// <summary>
/// Takes a string version of a MySql data type and returns its .NET common language runtime (CLR) counterpart
/// TODO: For MySql stored procedure support, this needs to be implemented.
/// Takes a string version of a PostgreSql data type and returns its .NET common language runtime (CLR) counterpart
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there are changes related to MySQL as well, can you move them in a separate PR?

Since, the PR title says it's for Postgres

/// TODO: For PostgreSql stored procedure support, this needs to be implemented.
/// </summary>
public override Type SqlToCLRType(string sqlType)
{
throw new NotImplementedException();
switch (sqlType.ToLower())
{
case "boolean":
case "bool":
return typeof(bool);

case "smallint":
return typeof(short);

case "integer":
case "int":
return typeof(int);

case "bigint":
return typeof(long);

case "real":
return typeof(float);

case "double precision":
return typeof(double);

case "numeric":
case "decimal":
return typeof(decimal);

case "money":
return typeof(decimal);

case "character varying":
case "varchar":
case "character":
case "char":
case "text":
return typeof(string);

case "bytea":
return typeof(byte[]);

case "date":
return typeof(DateTime);

case "timestamp":
case "timestamp without time zone":
return typeof(DateTime);

case "timestamp with time zone":
return typeof(DateTimeOffset);

case "time":
case "time without time zone":
return typeof(TimeSpan);

case "time with time zone":
return typeof(DateTimeOffset);

case "interval":
return typeof(TimeSpan);

case "uuid":
return typeof(Guid);

case "json":
case "jsonb":
return typeof(string);

case "xml":
return typeof(string);

case "inet":
return typeof(System.Net.IPAddress);

case "cidr":
return typeof(ValueTuple<System.Net.IPAddress, int>);

case "macaddr":
return typeof(System.Net.NetworkInformation.PhysicalAddress);

case "bit":
case "bit varying":
return typeof(BitArray);

case "point":
return typeof((double, double));

case "line":
return typeof(string); // Implement a custom type if needed

case "lseg":
return typeof((double, double)[]);

case "box":
return typeof((double, double)[]);

case "path":
return typeof((double, double)[]);

case "polygon":
return typeof((double, double)[]);

case "circle":
return typeof((double, double, double));

case "tsvector":
return typeof(string); // Implement a custom type if needed

case "tsquery":
return typeof(string); // Implement a custom type if needed

default:
throw new NotSupportedException($"The SQL type '{sqlType}' is not supported.");
}
}

}
}
Loading