1 /* 2 * Copyright 2015-2018 HuntLabs.cn 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 module hunt.sql.visitor.functions.OneParamFunctions; 17 18 // import hunt.sql.visitor.SQLEvalVisitor.EVAL_VALUE; 19 // import hunt.sql.visitor.SQLEvalVisitor.EVAL_VALUE_NULL; 20 21 22 import hunt.sql.ast.SQLExpr; 23 import hunt.sql.ast.expr.SQLMethodInvokeExpr; 24 import hunt.sql.visitor.SQLEvalVisitor; 25 import hunt.sql.visitor.SQLEvalVisitorUtils; 26 import hunt.sql.util.Utils; 27 import hunt.sql.visitor.functions.Function; 28 import hunt.Integer; 29 import hunt.Long; 30 import hunt.String; 31 import hunt.String; 32 import hunt.collection; 33 import std.conv; 34 import std.uni; 35 import std.digest.md; 36 import std.string; 37 import hunt.math; 38 import hunt.text; 39 40 import std.concurrency : initOnce; 41 42 public class OneParamFunctions : Function { 43 44 static OneParamFunctions instance() { 45 __gshared OneParamFunctions inst; 46 return initOnce!inst(new OneParamFunctions()); 47 } 48 49 // public static OneParamFunctions instance; 50 51 // static this() 52 // { 53 // instance = new OneParamFunctions(); 54 // } 55 56 public Object eval(SQLEvalVisitor visitor, SQLMethodInvokeExpr x) { 57 if (x.getParameters().size() == 0) { 58 return cast(Object)(SQLEvalVisitor.EVAL_ERROR); 59 } 60 61 SQLExpr param = x.getParameters().get(0); 62 param.accept(visitor); 63 64 Object paramValue = param.getAttributes().get(SQLEvalVisitor.EVAL_VALUE); 65 if (paramValue is null) { 66 return cast(Object)(SQLEvalVisitor.EVAL_ERROR); 67 } 68 69 if (paramValue == SQLEvalVisitor.EVAL_VALUE_NULL) { 70 return cast(Object)(SQLEvalVisitor.EVAL_VALUE_NULL); 71 } 72 73 string method = x.getMethodName(); 74 if ("md5".equalsIgnoreCase(method)) { 75 string text = paramValue.toString(); 76 return new String(cast(string)(md5Of(text))); 77 } 78 79 if ("bit_count".equalsIgnoreCase(method)) { 80 if (cast(BigInteger)(paramValue) !is null) { 81 return new Integer((cast(BigInteger) paramValue).bitCount()); 82 } 83 84 if (cast(BigDecimal)(paramValue) !is null) { 85 import hunt.Exceptions; 86 implementationMissing(false); 87 BigDecimal decimal = cast(BigDecimal) paramValue; 88 BigInteger bigInt = decimal.setScale(0, BigDecimal.ROUND_HALF_UP).toBigInteger(); 89 return new Integer(bigInt.bitCount()); 90 } 91 Long val = SQLEvalVisitorUtils.castToLong(paramValue); 92 return new Integer(Long.bitCount(val.longValue)); 93 } 94 95 if ("soundex".equalsIgnoreCase(method)) { 96 string text = paramValue.toString(); 97 return new String(soundex(text)); 98 } 99 100 if ("space".equalsIgnoreCase(method)) { 101 int intVal = (SQLEvalVisitorUtils.castToInteger(paramValue)).intValue; 102 char[] chars = new char[intVal]; 103 for (int i = 0; i < chars.length; ++i) { 104 chars[i] = ' '; 105 } 106 return new String(cast(string)chars); 107 } 108 109 throw new Exception(method); 110 } 111 112 public static string soundex(string str) { 113 if (str is null) { 114 return null; 115 } 116 str = clean(str); 117 if (str.length == 0) { 118 return str; 119 } 120 char[] out_p = ['0', '0', '0', '0']; 121 char last, mapped; 122 int incount = 1, count = 1; 123 out_p[0] = charAt(str, 0); 124 // getMappingCode() throws Exception 125 last = getMappingCode(str, 0); 126 while ((incount < str.length) && (count < out_p.length)) { 127 mapped = getMappingCode(str, incount++); 128 if (mapped != 0) { 129 if ((mapped != '0') && (mapped != last)) { 130 out_p[count++] = mapped; 131 } 132 last = mapped; 133 } 134 } 135 return cast(string)out_p; 136 } 137 138 static string clean(string str) { 139 if (str is null || str.length == 0) { 140 return str; 141 } 142 int len = cast(int)(str.length); 143 char[] chars = new char[len]; 144 int count = 0; 145 for (int i = 0; i < len; i++) { 146 if (isAlpha(charAt(str, i))) { 147 chars[count++] = charAt(str, i); 148 } 149 } 150 if (count == len) { 151 // return str.toUpperCase(java.util.Locale.ENGLISH); 152 return toUpper(str); 153 } 154 // return new String(chars, 0, count).toUpperCase(java.util.Locale.ENGLISH); 155 return toUpper(cast(string)chars[0..count]); 156 } 157 158 private static char getMappingCode(string str, int index) { 159 // map() throws Exception 160 char mappedChar = map(charAt(str, index)); 161 // HW rule check 162 if (index > 1 && mappedChar != '0') { 163 char hwChar = charAt(str, index - 1); 164 if ('H' == hwChar || 'W' == hwChar) { 165 char preHWChar = charAt(str, index - 2); 166 char firstCode = map(preHWChar); 167 if (firstCode == mappedChar || 'H' == preHWChar || 'W' == preHWChar) { 168 return 0; 169 } 170 } 171 } 172 return mappedChar; 173 } 174 175 private static char map(char ch) { 176 string soundexMapping = "01230120022455012623010202"; 177 int index = ch - 'A'; 178 if (index < 0 || index >= soundexMapping.length) { 179 throw new Exception("The character is not mapped: " ~ ch); 180 } 181 return charAt(soundexMapping, index); 182 } 183 184 185 }