using System.Linq.Expressions;
using SqlSugar;

namespace ServiceCenter.Extensions
{
    public static class SqlExtension
    {
        /// <summary>
        ///  不添加共享锁和排它锁，当这个选项生效后，可能读到未提交读的数据或“脏数据”，这个选项仅仅应用于SELECT语句
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static ISugarQueryable<T> NoLock<T>(this ISugarQueryable<T> obj)
        {
            return obj.With(SqlWith.NoLock);
        }

        /// <summary>
        ///  跳过已经加锁的数据行，这个选项将使事务读取数据时跳过那些已经被其他事务锁定的数据行，而不是阻塞直到其他事务释放锁，ReadPast仅仅应用于READ COMMITTED隔离性级别下事务操作中的SELECT语句操作。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static ISugarQueryable<T> ReadPast<T>(this ISugarQueryable<T> obj)
        {
            return obj.With(SqlWith.ReadPast);
        }

        /// <summary>
        ///  指定在读表中数据时设置更新锁（update lock）而不是设置共享锁，该锁一直保持到这个语句或整个事务结束，使用UpdLock的作用是允许用户先读取数据（而且不阻塞其他用户读数据），并且保证在后来再更新数据时，这一段时间内这些数据没有被其他用户修改。
        ///  默认持有行级更新锁
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static ISugarQueryable<T> UpdLock<T>(this ISugarQueryable<T> obj)
        {
            return obj.With("WITH(ROWLOCK)");
        }

        /// <summary>
        ///  跳过加锁数据行并指定在读表中数据时设置更新锁（update lock）而不是设置共享锁，该锁一直保持到这个语句或整个事务结束，使用UpdLock的作用是允许用户先读取数据（而且不阻塞其他用户读数据），并且保证在后来再更新数据时，这一段时间内这些数据没有被其他用户修改。
        ///  默认持有行级更新锁
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static ISugarQueryable<T> ReadPastUpdLock<T>(this ISugarQueryable<T> obj)
        {
            return obj.With("WITH(READPAST,ROWLOCK)");
        }

        /// <summary>
        ///  使用行级锁，而不使用粒度更粗的页级锁和表级锁。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static ISugarQueryable<T> RowLock<T>(this ISugarQueryable<T> obj)
        {
            return obj.With(SqlWith.RowLock);
        }

        /// <summary>
        ///  更新时使用行级锁
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="scope"></param>
        /// <param name="updateObj"></param>
        /// <returns></returns>
        public static IUpdateable<T> UpdateableRowLock<T>(this SqlSugarScopeProvider scope, T updateObj) where T : class, new() => scope.ScopedContext.Updateable<T>(updateObj).With(SqlWith.RowLock);

        public static bool UpdateWhereColumns<T>(this IUpdateable<T> db, Expression<Func<T, T>> columns,Expression<Func<T, bool>> whereExpression) where T : class, new()
        {
            return db.SetColumns(columns).Where(whereExpression).ExecuteCommand() > 0;
        }

        /// <summary>
        ///  更新时使用行级锁
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="scope"></param>
        /// <param name="updateObj"></param>
        /// <returns></returns>
        public static IUpdateable<T> UpdateableRowLock<T>(this SqlSugarScopeProvider scope, List<T> updateObj) where T : class, new() => scope.ScopedContext.Updateable<T>(updateObj).With(SqlWith.RowLock);

        /// <summary>
        ///  插入时使用行级锁
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="scope"></param>
        /// <param name="updateObj"></param>
        /// <returns></returns>
        public static IInsertable<T> InsertableRowLock<T>(this SqlSugarScopeProvider scope, T insertObj) where T : class, new() => scope.ScopedContext.Insertable<T>(insertObj).With(SqlWith.RowLock);

        /// <summary>
        ///  插入时使用行级锁
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="scope"></param>
        /// <param name="updateObj"></param>
        /// <returns></returns>
        public static IInsertable<T> InsertableRowLock<T>(this SqlSugarScopeProvider scope, List<T> insertObj) where T : class, new() => scope.ScopedContext.Insertable<T>(insertObj).With(SqlWith.RowLock);

        /// <summary>
        ///  删除时使用行级锁
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="scope"></param>
        /// <param name="deleteObj"></param>
        /// <returns></returns>
        public static IDeleteable<T> DeleteableRowLock<T>(this SqlSugarScopeProvider scope, T deleteObj) where T : class, new() => scope.ScopedContext.Deleteable<T>(deleteObj).With(SqlWith.RowLock);

        /// <summary>
        ///  删除时使用行级锁
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="scope"></param>
        /// <param name="deleteObj"></param>
        /// <returns></returns>
        public static IDeleteable<T> DeleteableRowLock<T>(this SqlSugarScopeProvider scope, List<T> deleteObj) where T : class, new() => scope.ScopedContext.Deleteable<T>(deleteObj).With(SqlWith.RowLock);
    }
}
