zhaolei
2020-11-20 921de2254ff5712a44ed8575ee8efe34252f6603
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
 
namespace PetaPoco.Internal
{
    internal static class ParametersHelper
    {
        private static Regex ParamPrefixRegex = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled);
        private static Regex NonWordStartRegex = new Regex(@"^\W*", RegexOptions.Compiled);
 
        public static string ReplaceParamPrefix(this string sql, string paramPrefix)
        {
            return ParamPrefixRegex.Replace(sql, m => paramPrefix + m.Value.Substring(1));
        }
 
        public static string EnsureParamPrefix(this int input, string paramPrefix)
            => $"{paramPrefix}{input}";
 
        public static string EnsureParamPrefix(this string input, string paramPrefix)
        {
            if (input.StartsWith(paramPrefix))
                return input;
            else
                return NonWordStartRegex.Replace(input, paramPrefix);
        }
 
        // Helper to handle named parameters from object properties
        public static string ProcessQueryParams(string sql, object[] args_src, List<object> args_dest)
        {
            return ParamPrefixRegex.Replace(sql, m =>
            {
                string param = m.Value.Substring(1);
 
                object arg_val;
 
                int paramIndex;
                if (int.TryParse(param, out paramIndex))
                {
                    // Numbered parameter
                    if (paramIndex < 0 || paramIndex >= args_src.Length)
                        throw new ArgumentOutOfRangeException(string.Format("Parameter '@{0}' specified but only {1} parameters supplied (in `{2}`)", paramIndex, args_src.Length,
                            sql));
                    arg_val = args_src[paramIndex];
                }
                else
                {
                    // Look for a property on one of the arguments with this name
                    bool found = false;
                    arg_val = null;
                    foreach (var o in args_src)
                    {
                        var pi = o.GetType().GetProperty(param);
                        if (pi != null)
                        {
                            arg_val = pi.GetValue(o, null);
                            found = true;
                            break;
                        }
                    }
 
                    if (!found)
                        throw new ArgumentException(string.Format("Parameter '@{0}' specified but none of the passed arguments have a property with this name (in '{1}')", param,
                            sql));
                }
 
                // Expand collections to parameter lists
                if (arg_val.IsEnumerable())
                {
                    var sb = new StringBuilder();
                    foreach (var i in (arg_val as System.Collections.IEnumerable))
                    {
                        sb.Append((sb.Length == 0 ? "@" : ",@") + args_dest.Count.ToString());
                        args_dest.Add(i);
                    }
 
                    return sb.ToString();
                }
                else
                {
                    args_dest.Add(arg_val);
                    return "@" + (args_dest.Count - 1).ToString();
                }
            });
        }
 
        private static bool IsEnumerable(this object input)
        {
            return (input as System.Collections.IEnumerable) != null && (input as string) == null && (input as byte[]) == null;
        }
 
        public static object[] ProcessStoredProcParams(IDbCommand cmd, object[] args, Action<IDbDataParameter, object, PropertyInfo> setParameterProperties)
        {
            // For a stored proc, we assume that we're only getting POCOs or parameters
            var result = new List<IDbDataParameter>();
 
            void ProcessArg(object arg)
            {
                if (arg.IsEnumerable())
                {
                    foreach (var singleArg in (arg as System.Collections.IEnumerable))
                    {
                        ProcessArg(singleArg);
                    }
                }
                else if (arg is IDbDataParameter)
                    result.Add((IDbDataParameter) arg);
                else
                {
                    var type = arg.GetType();
                    if (type.IsValueType || type == typeof(string))
                        throw new ArgumentException($"Value type or string passed as stored procedure argument: {arg}");
                    var readableProps = type.GetProperties().Where(p => p.CanRead);
                    foreach (var prop in readableProps)
                    {
                        var param = cmd.CreateParameter();
                        param.ParameterName = prop.Name;
                        setParameterProperties(param, prop.GetValue(arg, null), null);
                        result.Add(param);
                    }
                }
            }
 
            foreach (var arg in args)
            {
                ProcessArg(arg);
            }
 
            return result.ToArray();
        }
    }
}