mirror of https://github.com/Squidex/squidex.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
258 lines
6.8 KiB
258 lines
6.8 KiB
// ==========================================================================
|
|
// Squidex Headless CMS
|
|
// ==========================================================================
|
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
// All rights reserved. Licensed under the MIT license.
|
|
// ==========================================================================
|
|
|
|
using System.Collections;
|
|
using System.Text;
|
|
|
|
namespace Squidex.Infrastructure.Queries;
|
|
|
|
public class SqlDialect
|
|
{
|
|
private const string Tab = " ";
|
|
|
|
public virtual bool IsDuplicateIndexException(Exception exception, string name)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
public virtual string BuildSelectStatement(SqlQuery request)
|
|
{
|
|
var sb = new StringBuilder("SELECT");
|
|
|
|
sb.AppendLines(request.Fields, Tab);
|
|
sb.AppendLine($"FROM {FormatTable(request.Table)}");
|
|
|
|
if (request.Where.Count > 0)
|
|
{
|
|
var query = And(request.Where);
|
|
|
|
sb.AppendLine("WHERE");
|
|
sb.Append(Tab);
|
|
sb.Append(query);
|
|
sb.AppendLine();
|
|
}
|
|
|
|
if (request.Order.Count > 0)
|
|
{
|
|
sb.Append("ORDER BY");
|
|
sb.AppendLines(request.Order, Tab);
|
|
}
|
|
|
|
var pagination = FormatLimitOffset(request.Limit, request.Offset, request.Order.Count > 0);
|
|
|
|
if (!string.IsNullOrEmpty(pagination))
|
|
{
|
|
sb.AppendLine(pagination);
|
|
}
|
|
|
|
return sb.ToString();
|
|
}
|
|
|
|
public virtual string GeoIndex(string name, string table, string field)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
public virtual string TextIndex(string name, string table, string field)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
public virtual string TextIndexPrepare(string name)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
public virtual string FormatLimitOffset(long limit, long offset, bool hasOrder)
|
|
{
|
|
var hasLimit = limit > 0 && limit < long.MaxValue;
|
|
|
|
if (hasLimit && offset > 0)
|
|
{
|
|
return $"LIMIT {limit} OFFSET {offset}";
|
|
}
|
|
|
|
if (offset > 0)
|
|
{
|
|
return $"OFFSET {offset}";
|
|
}
|
|
|
|
if (hasLimit)
|
|
{
|
|
return $"LIMIT {limit}";
|
|
}
|
|
|
|
return string.Empty;
|
|
}
|
|
|
|
public virtual string? JsonColumnType()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public virtual string And(IEnumerable<string> parts)
|
|
{
|
|
return $"({string.Join(" AND ", parts)})";
|
|
}
|
|
|
|
public virtual string Or(IEnumerable<string> parts)
|
|
{
|
|
return $"({string.Join(" OR ", parts)})";
|
|
}
|
|
|
|
public virtual string Not(string part)
|
|
{
|
|
return $"NOT ({part})";
|
|
}
|
|
|
|
public virtual string SelectAll()
|
|
{
|
|
return "*";
|
|
}
|
|
|
|
public virtual string CountAll()
|
|
{
|
|
return $"COUNT(*) as {Field("Value", false)}";
|
|
}
|
|
|
|
public virtual string Field(PropertyPath path, bool isJson)
|
|
{
|
|
return $"{FormatField(path, isJson)}";
|
|
}
|
|
|
|
public virtual string OrderBy(PropertyPath path, SortOrder order, bool isJson)
|
|
{
|
|
return $"{FormatField(path, isJson)} {FormatOrder(order)}";
|
|
}
|
|
|
|
public virtual string Where(PropertyPath path, CompareOperator op, ClrValue value, SqlParams queryParameters, bool isJson)
|
|
{
|
|
return $"{FormatField(path, isJson)} {FormatOperator(op, value)} {FormatValues(op, value, queryParameters)}";
|
|
}
|
|
|
|
public virtual string WhereQuery(PropertyPath path, CompareOperator op, string query, bool isJson)
|
|
{
|
|
return $"{FormatField(path, isJson)} {FormatOperator(op, ClrValue.Null)} ({query})";
|
|
}
|
|
|
|
public virtual string WhereMatch(PropertyPath path, string query, SqlParams queryParameters)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
protected virtual string FormatValues(CompareOperator op, ClrValue value, SqlParams queryParameters)
|
|
{
|
|
if (!value.IsList && value.ValueType == ClrValueType.Null)
|
|
{
|
|
return "NULL";
|
|
}
|
|
|
|
string[] parameters;
|
|
if (value.IsList && value.Value is IEnumerable list)
|
|
{
|
|
parameters = list.Cast<object>().Select(AddParameter).ToArray();
|
|
}
|
|
else
|
|
{
|
|
parameters = [AddParameter(value.Value!)];
|
|
}
|
|
|
|
string AddParameter(object value)
|
|
{
|
|
value = FormatRawValue(value, op);
|
|
|
|
return queryParameters.AddPositional(value);
|
|
}
|
|
|
|
if (op == CompareOperator.In)
|
|
{
|
|
return $"({string.Join(", ", parameters)})";
|
|
}
|
|
|
|
return parameters[0];
|
|
}
|
|
|
|
protected virtual object FormatRawValue(object value, CompareOperator op)
|
|
{
|
|
switch (op)
|
|
{
|
|
case CompareOperator.StartsWith:
|
|
value = $"{value}%";
|
|
break;
|
|
case CompareOperator.EndsWith:
|
|
value = $"%{value}";
|
|
break;
|
|
case CompareOperator.Contains:
|
|
value = $"%{value}%";
|
|
break;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
protected virtual string FormatOperator(CompareOperator op, ClrValue value)
|
|
{
|
|
switch (op)
|
|
{
|
|
case CompareOperator.Equals when value.ValueType == ClrValueType.Null:
|
|
return "IS";
|
|
case CompareOperator.Equals:
|
|
return "=";
|
|
case CompareOperator.NotEquals when value.ValueType == ClrValueType.Null:
|
|
return "IS NOT";
|
|
case CompareOperator.NotEquals:
|
|
return "!=";
|
|
case CompareOperator.LessThan:
|
|
return "<";
|
|
case CompareOperator.LessThanOrEqual:
|
|
return "<=";
|
|
case CompareOperator.Contains:
|
|
return "LIKE";
|
|
case CompareOperator.EndsWith:
|
|
return "LIKE";
|
|
case CompareOperator.StartsWith:
|
|
return "LIKE";
|
|
case CompareOperator.GreaterThan:
|
|
return ">";
|
|
case CompareOperator.GreaterThanOrEqual:
|
|
return ">=";
|
|
case CompareOperator.In:
|
|
return "IN";
|
|
default:
|
|
ThrowHelper.NotSupportedException();
|
|
return null!;
|
|
}
|
|
}
|
|
|
|
protected virtual string FormatOrder(SortOrder order)
|
|
{
|
|
switch (order)
|
|
{
|
|
case SortOrder.Ascending:
|
|
return "ASC";
|
|
case SortOrder.Descending:
|
|
return "DESC";
|
|
default:
|
|
throw new ArgumentException("Invalid enum value.", nameof(order));
|
|
}
|
|
}
|
|
|
|
protected virtual string FormatTable(string tableName)
|
|
{
|
|
return tableName;
|
|
}
|
|
|
|
protected virtual string FormatField(PropertyPath path, bool isJson)
|
|
{
|
|
if (isJson)
|
|
{
|
|
throw new InvalidOperationException("JSON is not supported by basic dialect.");
|
|
}
|
|
|
|
return path[0];
|
|
}
|
|
}
|
|
|