|
|
|
@ -5,6 +5,7 @@ |
|
|
|
// All rights reserved. Licensed under the MIT license.
|
|
|
|
// ==========================================================================
|
|
|
|
|
|
|
|
using System.Text; |
|
|
|
using Squidex.Infrastructure.Queries; |
|
|
|
using SqlException = Microsoft.Data.SqlClient.SqlException; |
|
|
|
|
|
|
|
@ -87,45 +88,96 @@ public sealed class SqlServerDialect : SqlDialect |
|
|
|
{ |
|
|
|
if (isJson) |
|
|
|
{ |
|
|
|
var issNumeric = value.ValueType is |
|
|
|
var sqlPath = path.JsonPath(); |
|
|
|
var sqlOp = FormatOperator(op, value); |
|
|
|
var sqlRhs = FormatValues(op, value, queryParameters); |
|
|
|
|
|
|
|
var isNull = value.ValueType is ClrValueType.Null; |
|
|
|
var isBoolean = value.ValueType is ClrValueType.Boolean; |
|
|
|
var isNumeric = value.ValueType is |
|
|
|
ClrValueType.Single or |
|
|
|
ClrValueType.Double or |
|
|
|
ClrValueType.Int32 or |
|
|
|
ClrValueType.Int64; |
|
|
|
if (issNumeric) |
|
|
|
|
|
|
|
string ScalarCondition() |
|
|
|
{ |
|
|
|
var sqlPath = path.JsonPath(); |
|
|
|
var sqlOp = FormatOperator(op, value); |
|
|
|
var sqlRhs = FormatValues(op, value, queryParameters); |
|
|
|
if (isNull) |
|
|
|
{ |
|
|
|
if (op == CompareOperator.Equals) |
|
|
|
{ |
|
|
|
return $"JSON_QUERY({sqlPath}) IS NULL AND JSON_VALUE({sqlPath}) IS NULL"; |
|
|
|
} |
|
|
|
|
|
|
|
if (op == CompareOperator.NotEquals) |
|
|
|
{ |
|
|
|
return $"JSON_QUERY({sqlPath}) IS NOT NULL OR JSON_VALUE({sqlPath}) IS NOT NULL"; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return $"TRY_CAST(JSON_VALUE({sqlPath}) AS NUMERIC) {sqlOp} {sqlRhs}"; |
|
|
|
} |
|
|
|
if (isNumeric) |
|
|
|
{ |
|
|
|
return $"TRY_CAST(JSON_VALUE({sqlPath}) AS NUMERIC) {sqlOp} {sqlRhs}"; |
|
|
|
} |
|
|
|
|
|
|
|
var isBoolean = value.ValueType is ClrValueType.Boolean; |
|
|
|
if (isBoolean) |
|
|
|
{ |
|
|
|
var sqlPath = path.JsonPath(); |
|
|
|
var sqlOp = FormatOperator(op, value); |
|
|
|
var sqlRhs = FormatValues(op, value, queryParameters); |
|
|
|
if (isBoolean) |
|
|
|
{ |
|
|
|
return $"IIF(JSON_VALUE({sqlPath}) = 'true', 1, 0) {sqlOp} {sqlRhs}"; |
|
|
|
} |
|
|
|
|
|
|
|
return $"IIF(JSON_VALUE({sqlPath}) = 'true', 1, 0) {sqlOp} {sqlRhs}"; |
|
|
|
return base.Where(path, op, value, queryParameters, isJson); |
|
|
|
} |
|
|
|
|
|
|
|
var isNull = value.ValueType is ClrValueType.Null; |
|
|
|
if (isNull) |
|
|
|
string ArrayCondition(string field, string op) |
|
|
|
{ |
|
|
|
var sqlPath = path.JsonPath(); |
|
|
|
|
|
|
|
if (op == CompareOperator.Equals) |
|
|
|
if (isNumeric) |
|
|
|
{ |
|
|
|
return $"JSON_QUERY({sqlPath}) IS NULL AND JSON_VALUE({sqlPath}) IS NULL"; |
|
|
|
return $"TRY_CAST({field} AS NUMERIC) {op} {sqlRhs}"; |
|
|
|
} |
|
|
|
|
|
|
|
if (op == CompareOperator.NotEquals) |
|
|
|
if (isBoolean) |
|
|
|
{ |
|
|
|
return $"JSON_QUERY({sqlPath}) IS NOT NULL OR JSON_VALUE({sqlPath}) IS NOT NULL"; |
|
|
|
return $"IIF({field} = 'true', 1, 0) {op} {sqlRhs}"; |
|
|
|
} |
|
|
|
|
|
|
|
return $"{field} = {sqlRhs}"; |
|
|
|
} |
|
|
|
|
|
|
|
if (value.IsList && op == CompareOperator.In) |
|
|
|
{ |
|
|
|
return $"""
|
|
|
|
CASE WHEN LEFT(JSON_QUERY({sqlPath}), 1) = '[' |
|
|
|
THEN ( |
|
|
|
SELECT COUNT(*) |
|
|
|
FROM OPENJSON({sqlPath}) AS field_arr |
|
|
|
WHERE {ArrayCondition("field_arr.value", "IN")} |
|
|
|
) |
|
|
|
ELSE ( |
|
|
|
SELECT COUNT(*) |
|
|
|
WHERE {ScalarCondition()} |
|
|
|
) |
|
|
|
END > 0 |
|
|
|
""";
|
|
|
|
} |
|
|
|
|
|
|
|
if (op == CompareOperator.Equals) |
|
|
|
{ |
|
|
|
return $"""
|
|
|
|
CASE WHEN LEFT(JSON_QUERY({sqlPath}), 1) = '[' |
|
|
|
THEN ( |
|
|
|
SELECT COUNT(*) |
|
|
|
FROM OPENJSON({sqlPath}) AS field_arr |
|
|
|
WHERE {ArrayCondition("field_arr.value", "=")} |
|
|
|
) |
|
|
|
ELSE ( |
|
|
|
SELECT COUNT(*) |
|
|
|
WHERE {ScalarCondition()} |
|
|
|
) |
|
|
|
END > 0 |
|
|
|
""";
|
|
|
|
} |
|
|
|
|
|
|
|
return ScalarCondition(); |
|
|
|
} |
|
|
|
|
|
|
|
return base.Where(path, op, value, queryParameters, isJson); |
|
|
|
|