PageRenderTime 25ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/NetTiers/NetROS.Tiers.Data/Query/ExpressionParserBase.cs

http://napp.codeplex.com
C# | 345 lines | 202 code | 58 blank | 85 comment | 38 complexity | 5dada85e7f9dbe36ce355b5a9cef6600 MD5 | raw file
  1. #region Using Directives
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.Text;
  6. #endregion
  7. namespace NetROS.Tiers.Data
  8. {
  9. /// <summary>
  10. /// Provides the base functionality required to parse search terms.
  11. /// </summary>
  12. [CLSCompliant(true)]
  13. public abstract class ExpressionParserBase
  14. {
  15. #region Constructors
  16. /// <summary>
  17. /// Initializes a new instance of the ExpressionParserBase class.
  18. /// </summary>
  19. /// <param name="propertyName"></param>
  20. /// <param name="comparisonType"></param>
  21. /// <param name="ignoreCase"></param>
  22. protected ExpressionParserBase(String propertyName, SqlComparisonType comparisonType, bool ignoreCase)
  23. {
  24. PropertyName = propertyName;
  25. ComparisonType = comparisonType;
  26. IgnoreCase = ignoreCase;
  27. }
  28. #endregion Constructors
  29. #region Methods
  30. /// <summary>
  31. /// Appends the specified search text to the current expression.
  32. /// </summary>
  33. /// <param name="searchText">The search text to append.</param>
  34. protected void ParseCore(String searchText)
  35. {
  36. IList<String> quotedValues = new List<String>();
  37. int leftNumber = 0;
  38. int rightNumber = 0;
  39. int i = -1;
  40. // last param was a key word
  41. bool isKeyWord = false;
  42. // used to track if the first param is a key word
  43. // i.e., and or "john smith"
  44. int numParams = 0;
  45. // use AND to search all
  46. // i.e. John Smith would become John and Smith
  47. // however "John Smith" is one entity
  48. bool needToInsertAND = false;
  49. String outStr = ParseQuotes(searchText, quotedValues);
  50. //StringTokenizer tokenizer = new StringTokenizer(outStr, "(),\t\r\n", true);
  51. StringTokenizer tokenizer = new StringTokenizer(outStr, "{}~\t\r\n", true);
  52. String nextToken;
  53. while ( tokenizer.HasMoreTokens )
  54. {
  55. // trim token
  56. nextToken = tokenizer.NextToken;//.Trim();
  57. // left parenthesis
  58. if ( nextToken.Equals(SqlUtil.LEFT) )
  59. {
  60. leftNumber++;
  61. if ( needToInsertAND )
  62. {
  63. AppendAnd();
  64. }
  65. OpenGrouping();
  66. needToInsertAND = false;
  67. isKeyWord = false;
  68. }
  69. // right parenthesis
  70. else if ( nextToken.Equals(SqlUtil.RIGHT) )
  71. {
  72. rightNumber++;
  73. CloseGrouping();
  74. needToInsertAND = true;
  75. isKeyWord = false;
  76. }
  77. // comma
  78. else if ( nextToken.Equals(SqlUtil.COMMA) )
  79. {
  80. AppendOr();
  81. needToInsertAND = false;
  82. isKeyWord = false;
  83. }
  84. // token is a key word (such as AND, OR,...)
  85. else if ( IsKeyWord(nextToken) )
  86. {
  87. numParams++;
  88. // if this is the first parameter in the entire string
  89. // treat it as a regular param (not a key word)
  90. if ( numParams == 1 )
  91. {
  92. needToInsertAND = true;
  93. AppendSearchText(nextToken);
  94. }
  95. // if only two params
  96. else if ( ( numParams == 2 ) && ( tokenizer.CountTokens <= 1 ) )
  97. {
  98. AppendAnd();
  99. AppendSearchText(nextToken);
  100. }
  101. // if the last string was a key word
  102. else if ( isKeyWord )
  103. {
  104. needToInsertAND = true;
  105. // treat this param as a regular string, not a key word
  106. isKeyWord = false;
  107. AppendSearchText(nextToken);
  108. }
  109. else
  110. {
  111. // make sure this is not the last param, if so use AND to search all
  112. if ( tokenizer.CountTokens <= 1 )
  113. {
  114. AppendAnd();
  115. AppendSearchText(nextToken);
  116. }
  117. else
  118. {
  119. if ( SqlUtil.AND.Equals(nextToken, StringComparison.OrdinalIgnoreCase) )
  120. {
  121. AppendAnd();
  122. }
  123. else if ( SqlUtil.OR.Equals(nextToken, StringComparison.OrdinalIgnoreCase) )
  124. {
  125. AppendOr();
  126. }
  127. needToInsertAND = false;
  128. isKeyWord = true;
  129. }
  130. }
  131. }
  132. else if ( nextToken.Equals(" ") )
  133. {
  134. AppendSpace();
  135. }
  136. else if ( nextToken.Equals("") )
  137. {
  138. }
  139. // string in quotes
  140. else if ( nextToken.Equals(SqlUtil.TOKEN) )
  141. {
  142. numParams++;
  143. if ( needToInsertAND )
  144. {
  145. AppendAnd();
  146. }
  147. needToInsertAND = true;
  148. // if the search param string is like: "John Smith" and Jones
  149. // the and needs to be translated to a SQL "AND"
  150. isKeyWord = false;
  151. // get the next quoted string
  152. i++;
  153. AppendSearchText(quotedValues[i]);
  154. }
  155. // a regular string other than the above cases
  156. else
  157. {
  158. numParams++;
  159. if ( needToInsertAND )
  160. {
  161. AppendAnd();
  162. }
  163. needToInsertAND = true;
  164. isKeyWord = false;
  165. AppendSearchText(nextToken);
  166. }
  167. }
  168. if ( leftNumber != rightNumber )
  169. {
  170. throw new ArgumentException("Syntax Error: mismatched parenthesis.");
  171. }
  172. }
  173. /// <summary>
  174. /// Parses quoted search terms.
  175. /// </summary>
  176. /// <param name="searchText"></param>
  177. /// <param name="quotedValues"></param>
  178. /// <returns></returns>
  179. private String ParseQuotes(String searchText, IList<String> quotedValues)
  180. {
  181. // sanity check
  182. if ( String.IsNullOrEmpty(searchText) || searchText.IndexOf('|') < 0 )
  183. {
  184. return searchText;
  185. }
  186. String[] tokens = searchText.Split('|');
  187. StringBuilder sb = new StringBuilder();
  188. bool needEndQuotes = true;
  189. foreach ( String token in tokens )
  190. {
  191. needEndQuotes = !needEndQuotes;
  192. if ( needEndQuotes )
  193. {
  194. sb.Append(SqlUtil.TOKEN);
  195. quotedValues.Add(token);
  196. }
  197. else
  198. {
  199. sb.Append(token);
  200. }
  201. }
  202. if ( needEndQuotes )
  203. {
  204. throw new ArgumentException("Syntax Error: mismatched quotes.");
  205. }
  206. return sb.ToString();
  207. }
  208. /// <summary>
  209. /// Determines whether the specified word is a reserved keyword.
  210. /// </summary>
  211. /// <param name="word"></param>
  212. /// <returns></returns>
  213. private bool IsKeyWord(String word)
  214. {
  215. return ( word != null && (
  216. SqlUtil.AND.Equals(word, StringComparison.OrdinalIgnoreCase) ||
  217. SqlUtil.OR.Equals(word, StringComparison.OrdinalIgnoreCase)
  218. ));
  219. }
  220. #endregion Methods
  221. #region Abstract Methods
  222. /// <summary>
  223. /// Appends an OR expression.
  224. /// </summary>
  225. protected abstract void AppendOr();
  226. /// <summary>
  227. /// Appends an AND expression.
  228. /// </summary>
  229. protected abstract void AppendAnd();
  230. /// <summary>
  231. /// Appends an expression separator.
  232. /// </summary>
  233. protected abstract void AppendSpace();
  234. /// <summary>
  235. /// Appends a group opened expression.
  236. /// </summary>
  237. protected abstract void OpenGrouping();
  238. /// <summary>
  239. /// Appends a group closed expression.
  240. /// </summary>
  241. protected abstract void CloseGrouping();
  242. /// <summary>
  243. /// Appends the specified search text to the expression.
  244. /// </summary>
  245. /// <param name="searchText">The search text to append.</param>
  246. protected abstract void AppendSearchText(String searchText);
  247. #endregion Abstract Methods
  248. #region Properties
  249. /// <summary>
  250. /// The IgnoreCase member variable.
  251. /// </summary>
  252. private bool ignoreCase;
  253. /// <summary>
  254. /// Gets or sets the IgnoreCase property.
  255. /// </summary>
  256. public bool IgnoreCase
  257. {
  258. get { return ignoreCase; }
  259. set { ignoreCase = value; }
  260. }
  261. /// <summary>
  262. /// The PropertyName member variable.
  263. /// </summary>
  264. private String propertyName;
  265. /// <summary>
  266. /// Gets or sets the PropertyName property.
  267. /// </summary>
  268. public String PropertyName
  269. {
  270. get { return propertyName; }
  271. set { propertyName = value; }
  272. }
  273. /// <summary>
  274. /// The ComparisonType member variable.
  275. /// </summary>
  276. private SqlComparisonType comparisonType;
  277. /// <summary>
  278. /// Gets or sets the ComparisonType property.
  279. /// </summary>
  280. public SqlComparisonType ComparisonType
  281. {
  282. get { return comparisonType; }
  283. set { comparisonType = value; }
  284. }
  285. #endregion Properties
  286. }
  287. }