1 /**
2 * Copyright © DiamondMVC 2019
3 * License: MIT (https://github.com/DiamondMVC/Diamond/blob/master/LICENSE)
4 * Author: Jacob Jensen (bausshf)
5 */
6 module diamond.data.mapping.engines.sqlshared;
7 
8 import std.conv : to;
9 
10 import mysql;
11 
12 import diamond.database : DbParam;
13 
14 public
15 {
16   import diamond.data.mapping.engines.sqlshared.sqladapter;
17   import diamond.data.mapping.engines.sqlshared.sqlentityformatter;
18 }
19 
20 mixin template CreatePool(TPool, string extraParams = "")
21 {
22   /// Global pool lock to ensure we don't attempt to create a connection pool twice on same connection string.
23   private static shared globalPoolLock = new Object;
24 
25   static const poolFormat = q{
26     package(diamond.data.mapping.engines) TPool getPool(string connectionString)
27     {
28       auto pool = _pools.get(connectionString, null);
29 
30       if (!pool)
31       {
32         synchronized (globalPoolLock)
33         {
34           pool = new TPool(connectionString%s);
35 
36           _pools[connectionString] = pool;
37         }
38 
39         return getPool(connectionString);
40       }
41 
42       return pool;
43     }
44   };
45 
46   import std..string : format;
47 
48   mixin(poolFormat.format("," ~ extraParams));
49 }
50 
51 /**
52 * Prepares a specialized parameter sql.
53 * Params:
54 *   sql =            The sql.
55 *   params =         The params.
56 *   transformedSql = The newly transformed sql.
57 * Returns:
58 *   The raw db parameters, iff keepParameters is false.
59 */
60 package(diamond.data.mapping.engines) auto prepareSql(bool keepParameters = false)(string sql, DbParam[string] params, out string transformedSql)
61 {
62   transformedSql = "";
63 
64   static if (keepParameters)
65   {
66     return params;
67   }
68   else
69   {
70     string paramName = "";
71     bool selectParam = false;
72     DbParam[] sqlParams;
73 
74     foreach (i; 0 .. sql.length)
75     {
76       auto c = sql[i];
77 
78       if (c == 13) continue;
79 
80       bool isEnd = i == (sql.length - 1);
81 
82       if (c == '@')
83       {
84         paramName = "";
85         selectParam = true;
86       }
87       else if (selectParam && (
88         c == ';' || c == '=' ||
89         c == '+' || c == '-' ||
90         c == 9 || c == 13 ||
91         c == 10 || c == ' ' ||
92         c == 0 || c == '|' ||
93         c == '.' || c == '/' ||
94         c == '*' || c == '(' ||
95         c == ')' || c == '[' ||
96         c == ']' || c == ',' ||
97         c == '`' || c == 39
98       ))
99       {
100         if (paramName == "table")
101         {
102           transformedSql ~= params[paramName].get!string ~ to!string(c);
103           selectParam = false;
104           paramName = "";
105         }
106         else
107         {
108           sqlParams ~= params[paramName];
109           transformedSql ~= "?" ~ c;
110 
111           selectParam = false;
112           paramName = "";
113         }
114       }
115       else if (selectParam)
116       {
117         paramName ~= c;
118 
119         if (isEnd)
120         {
121           if (paramName == "table")
122           {
123             transformedSql ~= params[paramName].get!string ~ to!string(c);
124           }
125           else
126           {
127             sqlParams ~= params[paramName];
128             transformedSql ~= "?";
129           }
130         }
131       }
132       else
133       {
134         transformedSql ~= c;
135       }
136     }
137 
138     return sqlParams;
139   }
140 }