示例#1
0
        public override string ExpressionLambdaToSqlOther(Expression exp, ExpTSC tsc)
        {
            Func <Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);

            switch (exp.NodeType)
            {
            case ExpressionType.Convert:
                var operandExp = (exp as UnaryExpression)?.Operand;
                var gentype    = exp.Type.NullableTypeOrThis();
                if (gentype != operandExp.Type.NullableTypeOrThis())
                {
                    switch (exp.Type.NullableTypeOrThis().ToString())
                    {
                    //case "System.Boolean": return $"({getExp(operandExp)} not in ('0','false'))";
                    case "System.Byte": return($"cast({getExp(operandExp)} as number)");

                    case "System.Char": return($"substr(to_char({getExp(operandExp)}), 1, 1)");

                    case "System.DateTime": return($"to_timestamp({getExp(operandExp)},'YYYY-MM-DD HH24:MI:SS.FF6')");

                    case "System.Decimal": return($"cast({getExp(operandExp)} as number)");

                    case "System.Double": return($"cast({getExp(operandExp)} as number)");

                    case "System.Int16":
                    case "System.Int32":
                    case "System.Int64":
                    case "System.SByte": return($"cast({getExp(operandExp)} as number)");

                    case "System.Single": return($"cast({getExp(operandExp)} as number)");

                    case "System.String": return($"to_char({getExp(operandExp)})");

                    case "System.UInt16":
                    case "System.UInt32":
                    case "System.UInt64": return($"cast({getExp(operandExp)} as number)");

                    case "System.Guid": return($"substr(to_char({getExp(operandExp)}), 1, 36)");
                    }
                }
                break;

            case ExpressionType.Call:
                var callExp = exp as MethodCallExpression;

                switch (callExp.Method.Name)
                {
                case "Parse":
                case "TryParse":
                    switch (callExp.Method.DeclaringType.NullableTypeOrThis().ToString())
                    {
                    //case "System.Boolean": return $"({getExp(callExp.Arguments[0])} not in ('0','false'))";
                    case "System.Byte": return($"cast({getExp(callExp.Arguments[0])} as number)");

                    case "System.Char": return($"substr(to_char({getExp(callExp.Arguments[0])}), 1, 1)");

                    case "System.DateTime": return($"to_timestamp({getExp(callExp.Arguments[0])},'YYYY-MM-DD HH24:MI:SS.FF6')");

                    case "System.Decimal": return($"cast({getExp(callExp.Arguments[0])} as number)");

                    case "System.Double": return($"cast({getExp(callExp.Arguments[0])} as number)");

                    case "System.Int16":
                    case "System.Int32":
                    case "System.Int64":
                    case "System.SByte": return($"cast({getExp(callExp.Arguments[0])} as number)");

                    case "System.Single": return($"cast({getExp(callExp.Arguments[0])} as number)");

                    case "System.UInt16":
                    case "System.UInt32":
                    case "System.UInt64": return($"cast({getExp(callExp.Arguments[0])} as number)");

                    case "System.Guid": return($"substr(to_char({getExp(callExp.Arguments[0])}), 1, 36)");
                    }
                    break;

                case "NewGuid":
                    break;

                case "Next":
                    if (callExp.Object?.Type == typeof(Random))
                    {
                        return("cast(dbms_random.value*1000000000 as smallint)");
                    }
                    break;

                case "NextDouble":
                    if (callExp.Object?.Type == typeof(Random))
                    {
                        return("dbms_random.value");
                    }
                    break;

                case "Random":
                    if (callExp.Method.DeclaringType.IsNumberType())
                    {
                        return("dbms_random.value");
                    }
                    break;

                case "ToString":
                    if (callExp.Object != null)
                    {
                        return(callExp.Arguments.Count == 0 ? $"to_char({getExp(callExp.Object)})" : null);
                    }
                    break;
                }

                var objExp  = callExp.Object;
                var objType = objExp?.Type;
                if (objType?.FullName == "System.Byte[]")
                {
                    return(null);
                }

                var argIndex = 0;
                if (objType == null && callExp.Method.DeclaringType == typeof(Enumerable))
                {
                    objExp  = callExp.Arguments.FirstOrDefault();
                    objType = objExp?.Type;
                    argIndex++;
                }
                if (objType == null)
                {
                    objType = callExp.Method.DeclaringType;
                }
                if (objType != null || objType.IsArrayOrList())
                {
                    tsc?.SetMapTypeTmp(null);
                    var args1      = getExp(callExp.Arguments[argIndex]);
                    var oldMapType = tsc?.SetMapTypeReturnOld(tsc?.mapTypeTmp);
                    var left       = objExp == null ? null : getExp(objExp);
                    tsc.SetMapTypeReturnOld(oldMapType);
                    switch (callExp.Method.Name)
                    {
                    case "Contains":
                        //判断 in
                        return($"({args1}) in {left}");
                    }
                }
                break;

            case ExpressionType.NewArrayInit:
                var arrExp = exp as NewArrayExpression;
                var arrSb  = new StringBuilder();
                arrSb.Append("(");
                for (var a = 0; a < arrExp.Expressions.Count; a++)
                {
                    if (a > 0)
                    {
                        arrSb.Append(",");
                    }
                    arrSb.Append(getExp(arrExp.Expressions[a]));
                }
                if (arrSb.Length == 1)
                {
                    arrSb.Append("NULL");
                }
                return(arrSb.Append(")").ToString());

            case ExpressionType.ListInit:
                var listExp = exp as ListInitExpression;
                var listSb  = new StringBuilder();
                listSb.Append("(");
                for (var a = 0; a < listExp.Initializers.Count; a++)
                {
                    if (listExp.Initializers[a].Arguments.Any() == false)
                    {
                        continue;
                    }
                    if (a > 0)
                    {
                        listSb.Append(",");
                    }
                    listSb.Append(getExp(listExp.Initializers[a].Arguments.FirstOrDefault()));
                }
                if (listSb.Length == 1)
                {
                    listSb.Append("NULL");
                }
                return(listSb.Append(")").ToString());

            case ExpressionType.New:
                var newExp = exp as NewExpression;
                if (typeof(IList).IsAssignableFrom(newExp.Type))
                {
                    if (newExp.Arguments.Count == 0)
                    {
                        return("(NULL)");
                    }
                    if (typeof(IEnumerable).IsAssignableFrom(newExp.Arguments[0].Type) == false)
                    {
                        return("(NULL)");
                    }
                    return(getExp(newExp.Arguments[0]));
                }
                return(null);
            }
            return(null);
        }
示例#2
0
        public override string ExpressionLambdaToSqlOther(Expression exp, ExpTSC tsc)
        {
            Func <Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);

            switch (exp.NodeType)
            {
            case ExpressionType.Convert:
                var operandExp = (exp as UnaryExpression)?.Operand;
                var gentype    = exp.Type.NullableTypeOrThis();
                if (gentype != operandExp.Type.NullableTypeOrThis())
                {
                    switch (gentype.ToString())
                    {
                    case "System.Boolean": return(_utils.Adapter.LambdaConvert_ToBoolean(operandExp.Type, getExp(operandExp)));

                    case "System.Byte": return(_utils.Adapter.LambdaConvert_ToByte(operandExp.Type, getExp(operandExp)));

                    case "System.Char": return(_utils.Adapter.LambdaConvert_ToChar(operandExp.Type, getExp(operandExp)));

                    case "System.DateTime": return(_utils.Adapter.LambdaConvert_ToDateTime(operandExp.Type, getExp(operandExp)));

                    case "System.Decimal": return(_utils.Adapter.LambdaConvert_ToDecimal(operandExp.Type, getExp(operandExp)));

                    case "System.Double": return(_utils.Adapter.LambdaConvert_ToDouble(operandExp.Type, getExp(operandExp)));

                    case "System.Int16": return(_utils.Adapter.LambdaConvert_ToInt16(operandExp.Type, getExp(operandExp)));

                    case "System.Int32": return(_utils.Adapter.LambdaConvert_ToInt32(operandExp.Type, getExp(operandExp)));

                    case "System.Int64": return(_utils.Adapter.LambdaConvert_ToInt64(operandExp.Type, getExp(operandExp)));

                    case "System.SByte": return(_utils.Adapter.LambdaConvert_ToSByte(operandExp.Type, getExp(operandExp)));

                    case "System.Single": return(_utils.Adapter.LambdaConvert_ToSingle(operandExp.Type, getExp(operandExp)));

                    case "System.String": return(_utils.Adapter.LambdaConvert_ToString(operandExp.Type, getExp(operandExp)));

                    case "System.UInt16": return(_utils.Adapter.LambdaConvert_ToUInt16(operandExp.Type, getExp(operandExp)));

                    case "System.UInt32": return(_utils.Adapter.LambdaConvert_ToUInt32(operandExp.Type, getExp(operandExp)));

                    case "System.UInt64": return(_utils.Adapter.LambdaConvert_ToUInt64(operandExp.Type, getExp(operandExp)));

                    case "System.Guid": return(_utils.Adapter.LambdaConvert_ToGuid(operandExp.Type, getExp(operandExp)));
                    }
                }
                break;

            case ExpressionType.Call:
                var callExp = exp as MethodCallExpression;

                switch (callExp.Method.Name)
                {
                case "Parse":
                case "TryParse":
                    switch (callExp.Method.DeclaringType.NullableTypeOrThis().ToString())
                    {
                    case "System.Boolean": return(_utils.Adapter.LambdaConvert_ToBoolean(callExp.Method.DeclaringType, getExp(callExp.Arguments[0])));

                    case "System.Byte": return(_utils.Adapter.LambdaConvert_ToByte(callExp.Method.DeclaringType, getExp(callExp.Arguments[0])));

                    case "System.Char": return(_utils.Adapter.LambdaConvert_ToChar(callExp.Method.DeclaringType, getExp(callExp.Arguments[0])));

                    case "System.DateTime": return(_utils.Adapter.LambdaConvert_ToDateTime(callExp.Method.DeclaringType, getExp(callExp.Arguments[0])));

                    case "System.Decimal": return(_utils.Adapter.LambdaConvert_ToDecimal(callExp.Method.DeclaringType, getExp(callExp.Arguments[0])));

                    case "System.Double": return(_utils.Adapter.LambdaConvert_ToDouble(callExp.Method.DeclaringType, getExp(callExp.Arguments[0])));

                    case "System.Int16": return(_utils.Adapter.LambdaConvert_ToInt16(callExp.Method.DeclaringType, getExp(callExp.Arguments[0])));

                    case "System.Int32": return(_utils.Adapter.LambdaConvert_ToInt32(callExp.Method.DeclaringType, getExp(callExp.Arguments[0])));

                    case "System.Int64": return(_utils.Adapter.LambdaConvert_ToInt64(callExp.Method.DeclaringType, getExp(callExp.Arguments[0])));

                    case "System.SByte": return(_utils.Adapter.LambdaConvert_ToSByte(callExp.Method.DeclaringType, getExp(callExp.Arguments[0])));

                    case "System.Single": return(_utils.Adapter.LambdaConvert_ToSingle(callExp.Method.DeclaringType, getExp(callExp.Arguments[0])));

                    case "System.UInt16": return(_utils.Adapter.LambdaConvert_ToUInt16(callExp.Method.DeclaringType, getExp(callExp.Arguments[0])));

                    case "System.UInt32": return(_utils.Adapter.LambdaConvert_ToUInt32(callExp.Method.DeclaringType, getExp(callExp.Arguments[0])));

                    case "System.UInt64": return(_utils.Adapter.LambdaConvert_ToUInt64(callExp.Method.DeclaringType, getExp(callExp.Arguments[0])));

                    case "System.Guid": return(_utils.Adapter.LambdaConvert_ToGuid(callExp.Method.DeclaringType, getExp(callExp.Arguments[0])));
                    }
                    break;

                case "NewGuid":
                    switch (callExp.Method.DeclaringType.NullableTypeOrThis().ToString())
                    {
                    case "System.Guid": return(_utils.Adapter.LambdaGuid_NewGuid);
                    }
                    break;

                case "Next":
                    if (callExp.Object?.Type == typeof(Random))
                    {
                        return(_utils.Adapter.LambdaRandom_Next);
                    }
                    break;

                case "NextDouble":
                    if (callExp.Object?.Type == typeof(Random))
                    {
                        return(_utils.Adapter.LambdaRandom_NextDouble);
                    }
                    break;

                case "Random":
                    if (callExp.Method.DeclaringType.IsNumberType())
                    {
                        return(_utils.Adapter.LambdaRandom_NextDouble);
                    }
                    break;

                case "ToString":
                    if (callExp.Object != null)
                    {
                        return(callExp.Arguments.Count == 0 ? _utils.Adapter.LambdaConvert_ToString(callExp.Object.Type, getExp(callExp.Object)) : null);
                    }
                    break;
                }

                var objExp  = callExp.Object;
                var objType = objExp?.Type;
                if (objType?.FullName == "System.Byte[]")
                {
                    return(null);
                }

                var argIndex = 0;
                if (objType == null && callExp.Method.DeclaringType == typeof(Enumerable))
                {
                    objExp  = callExp.Arguments.FirstOrDefault();
                    objType = objExp?.Type;
                    argIndex++;
                }
                if (objType == null)
                {
                    objType = callExp.Method.DeclaringType;
                }
                if (objType != null || objType.IsArrayOrList())
                {
                    tsc?.SetMapTypeTmp(null);
                    var args1      = getExp(callExp.Arguments[argIndex]);
                    var oldMapType = tsc?.SetMapTypeReturnOld(tsc?.mapTypeTmp);
                    var left       = objExp == null ? null : getExp(objExp);
                    tsc.SetMapTypeReturnOld(oldMapType);
                    switch (callExp.Method.Name)
                    {
                    case "Contains":
                        //判断 in
                        return($"({args1}) in {left}");
                    }
                }
                break;

            case ExpressionType.NewArrayInit:
                var arrExp = exp as NewArrayExpression;
                var arrSb  = new StringBuilder();
                arrSb.Append("(");
                for (var a = 0; a < arrExp.Expressions.Count; a++)
                {
                    if (a > 0)
                    {
                        arrSb.Append(",");
                    }
                    arrSb.Append(getExp(arrExp.Expressions[a]));
                }
                if (arrSb.Length == 1)
                {
                    arrSb.Append("NULL");
                }
                return(arrSb.Append(")").ToString());

            case ExpressionType.ListInit:
                var listExp = exp as ListInitExpression;
                var listSb  = new StringBuilder();
                listSb.Append("(");
                for (var a = 0; a < listExp.Initializers.Count; a++)
                {
                    if (listExp.Initializers[a].Arguments.Any() == false)
                    {
                        continue;
                    }
                    if (a > 0)
                    {
                        listSb.Append(",");
                    }
                    listSb.Append(getExp(listExp.Initializers[a].Arguments.FirstOrDefault()));
                }
                if (listSb.Length == 1)
                {
                    listSb.Append("NULL");
                }
                return(listSb.Append(")").ToString());

            case ExpressionType.New:
                var newExp = exp as NewExpression;
                if (typeof(IList).IsAssignableFrom(newExp.Type))
                {
                    if (newExp.Arguments.Count == 0)
                    {
                        return("(NULL)");
                    }
                    if (typeof(IEnumerable).IsAssignableFrom(newExp.Arguments[0].Type) == false)
                    {
                        return("(NULL)");
                    }
                    return(getExp(newExp.Arguments[0]));
                }
                return(null);
            }
            return(null);
        }
        public override string ExpressionLambdaToSqlOther(Expression exp, ExpTSC tsc)
        {
            Func <Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);

            switch (exp.NodeType)
            {
            case ExpressionType.Convert:
                var operandExp = (exp as UnaryExpression)?.Operand;
                var gentype    = exp.Type.NullableTypeOrThis();
                if (gentype != operandExp.Type.NullableTypeOrThis())
                {
                    switch (exp.Type.NullableTypeOrThis().ToString())
                    {
                    case "System.Boolean": return($"(({getExp(operandExp)})::varchar not in ('0','false','f','no'))");

                    case "System.Byte": return($"({getExp(operandExp)})::int2");

                    case "System.Char": return($"substr(({getExp(operandExp)})::char, 1, 1)");

                    case "System.DateTime": return($"({getExp(operandExp)})::timestamp");

                    case "System.Decimal": return($"({getExp(operandExp)})::numeric");

                    case "System.Double": return($"({getExp(operandExp)})::float8");

                    case "System.Int16": return($"({getExp(operandExp)})::int2");

                    case "System.Int32": return($"({getExp(operandExp)})::int4");

                    case "System.Int64": return($"({getExp(operandExp)})::int8");

                    case "System.SByte": return($"({getExp(operandExp)})::int2");

                    case "System.Single": return($"({getExp(operandExp)})::float4");

                    case "System.String": return($"({getExp(operandExp)})::varchar");

                    case "System.UInt16": return($"({getExp(operandExp)})::int2");

                    case "System.UInt32": return($"({getExp(operandExp)})::int4");

                    case "System.UInt64": return($"({getExp(operandExp)})::int8");

                    case "System.Guid": return($"({getExp(operandExp)})::uuid");
                    }
                }
                break;

            case ExpressionType.ArrayLength:
                var arrOperExp = getExp((exp as UnaryExpression).Operand);
                if (arrOperExp.StartsWith("(") || arrOperExp.EndsWith(")"))
                {
                    return($"array_length(array[{arrOperExp.TrimStart('(').TrimEnd(')')}],1)");
                }
                return($"case when {arrOperExp} is null then 0 else array_length({arrOperExp},1) end");

            case ExpressionType.Call:
                var callExp = exp as MethodCallExpression;

                switch (callExp.Method.Name)
                {
                case "Parse":
                case "TryParse":
                    switch (callExp.Method.DeclaringType.NullableTypeOrThis().ToString())
                    {
                    case "System.Boolean": return($"(({getExp(callExp.Arguments[0])})::varchar not in ('0','false','f','no'))");

                    case "System.Byte": return($"({getExp(callExp.Arguments[0])})::int2");

                    case "System.Char": return($"substr(({getExp(callExp.Arguments[0])})::char, 1, 1)");

                    case "System.DateTime": return($"({getExp(callExp.Arguments[0])})::timestamp");

                    case "System.Decimal": return($"({getExp(callExp.Arguments[0])})::numeric");

                    case "System.Double": return($"({getExp(callExp.Arguments[0])})::float8");

                    case "System.Int16": return($"({getExp(callExp.Arguments[0])})::int2");

                    case "System.Int32": return($"({getExp(callExp.Arguments[0])})::int4");

                    case "System.Int64": return($"({getExp(callExp.Arguments[0])})::int8");

                    case "System.SByte": return($"({getExp(callExp.Arguments[0])})::int2");

                    case "System.Single": return($"({getExp(callExp.Arguments[0])})::float4");

                    case "System.UInt16": return($"({getExp(callExp.Arguments[0])})::int2");

                    case "System.UInt32": return($"({getExp(callExp.Arguments[0])})::int4");

                    case "System.UInt64": return($"({getExp(callExp.Arguments[0])})::int8");

                    case "System.Guid": return($"({getExp(callExp.Arguments[0])})::uuid");
                    }
                    break;

                case "NewGuid":
                    break;

                case "Next":
                    if (callExp.Object?.Type == typeof(Random))
                    {
                        return("(random()*1000000000)::int4");
                    }
                    break;

                case "NextDouble":
                    if (callExp.Object?.Type == typeof(Random))
                    {
                        return("random()");
                    }
                    break;

                case "Random":
                    if (callExp.Method.DeclaringType.IsNumberType())
                    {
                        return("random()");
                    }
                    break;

                case "ToString":
                    if (callExp.Object != null)
                    {
                        return(callExp.Arguments.Count == 0 ? $"({getExp(callExp.Object)})::varchar" : null);
                    }
                    break;
                }

                var objExp  = callExp.Object;
                var objType = objExp?.Type;
                if (objType?.FullName == "System.Byte[]")
                {
                    return(null);
                }

                var argIndex = 0;
                if (objType == null && callExp.Method.DeclaringType == typeof(Enumerable))
                {
                    objExp  = callExp.Arguments.FirstOrDefault();
                    objType = objExp?.Type;
                    argIndex++;
                }
                if (objType == null)
                {
                    objType = callExp.Method.DeclaringType;
                }
                if (objType != null || objType.IsArrayOrList())
                {
                    string left = null;
                    switch (objType.FullName)
                    {
                    case "Newtonsoft.Json.Linq.JToken":
                    case "Newtonsoft.Json.Linq.JObject":
                    case "Newtonsoft.Json.Linq.JArray":
                        left = objExp == null ? null : getExp(objExp);
                        switch (callExp.Method.Name)
                        {
                        case "Any": return($"(jsonb_array_length(coalesce({left},'[]')) > 0)");

                        case "Contains":
                            var json = getExp(callExp.Arguments[argIndex]);
                            if (objType == typeof(JArray))
                            {
                                return($"(coalesce({left},'[]') ? ({json})::varchar)");
                            }
                            if (json.StartsWith("'") && json.EndsWith("'"))
                            {
                                return($"(coalesce({left},'{{}}') @> {_common.FormatSql("{0}", JToken.Parse(json.Trim('\'')))})");
                            }
                            return($"(coalesce({left},'{{}}') @> ({json})::jsonb)");

                        case "ContainsKey": return($"(coalesce({left},'{{}}') ? {getExp(callExp.Arguments[argIndex])})");

                        case "Concat":
                            var right2 = getExp(callExp.Arguments[argIndex]);
                            return($"(coalesce({left},'{{}}') || {right2})");

                        case "LongCount":
                        case "Count": return($"jsonb_array_length(coalesce({left},'[]'))");

                        case "Parse":
                            var json2 = getExp(callExp.Arguments[argIndex]);
                            if (json2.StartsWith("'") && json2.EndsWith("'"))
                            {
                                return(_common.FormatSql("{0}", JToken.Parse(json2.Trim('\''))));
                            }
                            return($"({json2})::jsonb");
                        }
                        break;
                    }
                    if (objType.FullName == typeof(Dictionary <string, string>).FullName)
                    {
                        left = objExp == null ? null : getExp(objExp);
                        switch (callExp.Method.Name)
                        {
                        case "Contains":
                            var right = getExp(callExp.Arguments[argIndex]);
                            return($"({left} @> ({right}))");

                        case "ContainsKey": return($"({left} ? {getExp(callExp.Arguments[argIndex])})");

                        case "Concat": return($"({left} || {getExp(callExp.Arguments[argIndex])})");

                        case "GetLength":
                        case "GetLongLength":
                        case "Count": return($"case when {left} is null then 0 else array_length(akeys({left}),1) end");

                        case "Keys": return($"akeys({left})");

                        case "Values": return($"avals({left})");
                        }
                    }
                    switch (callExp.Method.Name)
                    {
                    case "Any":
                        left = objExp == null ? null : getExp(objExp);
                        if (left.StartsWith("(") || left.EndsWith(")"))
                        {
                            left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
                        }
                        return($"(case when {left} is null then 0 else array_length({left},1) end > 0)");

                    case "Contains":
                        tsc?.SetMapTypeTmp(null);
                        var args1      = getExp(callExp.Arguments[argIndex]);
                        var oldMapType = tsc?.SetMapTypeReturnOld(tsc?.mapTypeTmp);
                        left = objExp == null ? null : getExp(objExp);
                        tsc.SetMapTypeReturnOld(oldMapType);
                        //判断 in 或 array @> array
                        if (left.StartsWith("array[") || left.EndsWith("]"))
                        {
                            return($"{args1} in ({left.Substring(6, left.Length - 7)})");
                        }
                        if (left.StartsWith("(") || left.EndsWith(")"))
                        {
                            return($"{args1} in {left}");
                        }
                        if (args1.StartsWith("(") || args1.EndsWith(")"))
                        {
                            args1 = $"array[{args1.TrimStart('(').TrimEnd(')')}]";
                        }
                        args1 = $"array[{args1}]";
                        if (objExp != null)
                        {
                            var dbinfo = _common._orm.CodeFirst.GetDbInfo(objExp.Type);
                            if (dbinfo.HasValue)
                            {
                                args1 = $"{args1}::{dbinfo.Value.dbtype}";
                            }
                        }
                        return($"({left} @> {args1})");

                    case "Concat":
                        left = objExp == null ? null : getExp(objExp);
                        if (left.StartsWith("(") || left.EndsWith(")"))
                        {
                            left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
                        }
                        var right2 = getExp(callExp.Arguments[argIndex]);
                        if (right2.StartsWith("(") || right2.EndsWith(")"))
                        {
                            right2 = $"array[{right2.TrimStart('(').TrimEnd(')')}]";
                        }
                        return($"({left} || {right2})");

                    case "GetLength":
                    case "GetLongLength":
                    case "Length":
                    case "Count":
                        left = objExp == null ? null : getExp(objExp);
                        if (left.StartsWith("(") || left.EndsWith(")"))
                        {
                            left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
                        }
                        return($"case when {left} is null then 0 else array_length({left},1) end");
                    }
                }
                break;

            case ExpressionType.MemberAccess:
                var memExp       = exp as MemberExpression;
                var memParentExp = memExp.Expression?.Type;
                if (memParentExp?.FullName == "System.Byte[]")
                {
                    return(null);
                }
                if (memParentExp != null)
                {
                    if (memParentExp.IsArray == true)
                    {
                        var left = getExp(memExp.Expression);
                        if (left.StartsWith("(") || left.EndsWith(")"))
                        {
                            left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
                        }
                        switch (memExp.Member.Name)
                        {
                        case "Length":
                        case "Count": return($"case when {left} is null then 0 else array_length({left},1) end");
                        }
                    }
                    switch (memParentExp.FullName)
                    {
                    case "Newtonsoft.Json.Linq.JToken":
                    case "Newtonsoft.Json.Linq.JObject":
                    case "Newtonsoft.Json.Linq.JArray":
                        var left = getExp(memExp.Expression);
                        switch (memExp.Member.Name)
                        {
                        case "Count": return($"jsonb_array_length(coalesce({left},'[]'))");
                        }
                        break;
                    }
                    if (memParentExp.FullName == typeof(Dictionary <string, string>).FullName)
                    {
                        var left = getExp(memExp.Expression);
                        switch (memExp.Member.Name)
                        {
                        case "Count": return($"case when {left} is null then 0 else array_length(akeys({left}),1) end");

                        case "Keys": return($"akeys({left})");

                        case "Values": return($"avals({left})");
                        }
                    }
                }
                break;

            case ExpressionType.NewArrayInit:
                var arrExp = exp as NewArrayExpression;
                var arrSb  = new StringBuilder();
                arrSb.Append("array[");
                for (var a = 0; a < arrExp.Expressions.Count; a++)
                {
                    if (a > 0)
                    {
                        arrSb.Append(",");
                    }
                    arrSb.Append(getExp(arrExp.Expressions[a]));
                }
                if (arrSb.Length == 1)
                {
                    arrSb.Append("NULL");
                }
                return(arrSb.Append("]").ToString());

            case ExpressionType.ListInit:
                var listExp = exp as ListInitExpression;
                var listSb  = new StringBuilder();
                listSb.Append("(");
                for (var a = 0; a < listExp.Initializers.Count; a++)
                {
                    if (listExp.Initializers[a].Arguments.Any() == false)
                    {
                        continue;
                    }
                    if (a > 0)
                    {
                        listSb.Append(",");
                    }
                    listSb.Append(getExp(listExp.Initializers[a].Arguments.FirstOrDefault()));
                }
                if (listSb.Length == 1)
                {
                    listSb.Append("NULL");
                }
                return(listSb.Append(")").ToString());

            case ExpressionType.New:
                var newExp = exp as NewExpression;
                if (typeof(IList).IsAssignableFrom(newExp.Type))
                {
                    if (newExp.Arguments.Count == 0)
                    {
                        return("(NULL)");
                    }
                    if (typeof(IEnumerable).IsAssignableFrom(newExp.Arguments[0].Type) == false)
                    {
                        return("(NULL)");
                    }
                    return(getExp(newExp.Arguments[0]));
                }
                return(null);
            }
            return(null);
        }