using System.Text; using Elsa.Common.Entities; using Elsa.Common.Models; using Elsa.Dapper.Contracts; namespace Elsa.Dapper.Abstractions; /// /// Provides a base implementation of , where the dialect defaults to SQLite. /// public abstract class SqlDialectBase : ISqlDialect { /// public virtual string From(string table) => From(table, "*"); /// public virtual string From(string table, params string[] fields) { var fieldList = string.Join(", ", fields); return $"select {fieldList} from {table} where 1=1"; } /// public string Delete(string table) => $"delete from {table} where 1=1"; /// public string Count(string table) => Count("*", table); /// public string Count(string fieldExpression, string table) => $"select COUNT({fieldExpression}) from {table} where 1=1"; /// public virtual string And(string field) => $"and {field} = @{field}"; /// public virtual string AndNot(string field) => $"and not {field} = @{field}"; /// public virtual string And(string field, string[] fieldParamNames) => $"and {field} in ({string.Join(", ", fieldParamNames)})"; /// public virtual string AndNot(string field, string[] fieldParamNames) => $"and {field} not in ({string.Join(", ", fieldParamNames)})"; /// public string IsNull(string field) => $"and {field} is null"; /// public string IsNotNull(string field) => $"and {field} is not null"; /// public virtual string OrderBy(string field, OrderDirection direction) { var directionString = direction == OrderDirection.Ascending ? "asc" : "desc"; return $"order by {field} {directionString}"; } /// public virtual string Skip(int count) => $"offset {count} rows"; /// public virtual string Take(int count) => $"fetch next {count} rows only"; /// public virtual string Page(PageArgs pageArgs) { var sb = new StringBuilder(); // Attention: the order is important here for SQL Server (OFFSET before FETCH NEXT). if (pageArgs.Offset != null) sb.AppendLine(Skip(pageArgs.Offset.Value)); if (pageArgs.Limit != null) sb.AppendLine(Take(pageArgs.Limit.Value)); return sb.ToString(); } /// public string Insert(string table, string[] fields, Func? getParamName = default) { getParamName ??= x => x; var fieldList = string.Join(", ", fields); var fieldParamNames = fields.Select(x => $"@{getParamName(x)}"); var fieldParamList = string.Join(", ", fieldParamNames); return $"INSERT INTO {table} ({fieldList}) VALUES ({fieldParamList});"; } /// public virtual string Upsert(string table, string primaryKeyField, string[] fields, Func? getParamName = default) { getParamName ??= x => x; var fieldList = string.Join(", ", fields); var fieldParamNames = fields.Select(x => $"@{getParamName(x)}"); var fieldParamList = string.Join(", ", fieldParamNames); return @$" MERGE INTO {table} WITH (HOLDLOCK) AS Target USING (VALUES (@{getParamName(primaryKeyField)}, {fieldParamList})) AS Source ({primaryKeyField}, {fieldList}) ON Target.{primaryKeyField} = Source.{primaryKeyField} WHEN MATCHED THEN UPDATE SET {string.Join(", ", fields.Select(x => $"{x} = Source.{x}"))} WHEN NOT MATCHED THEN INSERT ({primaryKeyField}, {fieldList}) VALUES (Source.{primaryKeyField}, {string.Join(", ", fields.Select(x => $"Source.{x}"))});"; } }