Author: cbegin
Date: Sat May  9 16:35:37 2009
New Revision: 773245

URL: http://svn.apache.org/viewvc?rev=773245&view=rev
Log:
Added parser for dynamic SQL (not hooked in yet)

Modified:
    ibatis/trunk/java/ibatis-3/TODO
    
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/BaseParser.java
    
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/SequentialMapperBuilder.java
    
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLMapperConfigParser.java
    
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLMapperParser.java
    
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLStatementParser.java
    ibatis/trunk/java/ibatis-3/version.properties

Modified: ibatis/trunk/java/ibatis-3/TODO
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/TODO?rev=773245&r1=773244&r2=773245&view=diff
==============================================================================
--- ibatis/trunk/java/ibatis-3/TODO (original)
+++ ibatis/trunk/java/ibatis-3/TODO Sat May  9 16:35:37 2009
@@ -1,19 +1,10 @@
 ###################################
-#          TODO List              #
+#          TO-DO List             #
 ###################################
 
 Required:
 
 * Return selectKey or autogen key from session.insert()
-* Dynamic SQL XML Parser
-    <where>
-    <set>
-    <prefix insert removeFirst>
-    <foreach item index open close separator>
-    <if test>
-    <choose>
-      <when test>
-      <otherwise>
 
 Nice to Have:
 

Modified: 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/BaseParser.java
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/BaseParser.java?rev=773245&r1=773244&r2=773245&view=diff
==============================================================================
--- 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/BaseParser.java
 (original)
+++ 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/BaseParser.java
 Sat May  9 16:35:37 2009
@@ -3,7 +3,7 @@
 import org.apache.ibatis.mapping.*;
 import org.apache.ibatis.type.*;
 
-public class BaseParser {
+public abstract class BaseParser {
   protected final Configuration configuration;
   protected final TypeAliasRegistry typeAliasRegistry;
   protected final TypeHandlerRegistry typeHandlerRegistry;

Modified: 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/SequentialMapperBuilder.java
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/SequentialMapperBuilder.java?rev=773245&r1=773244&r2=773245&view=diff
==============================================================================
--- 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/SequentialMapperBuilder.java
 (original)
+++ 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/SequentialMapperBuilder.java
 Sat May  9 16:35:37 2009
@@ -227,16 +227,16 @@
     configuration.addMappedStatement(statement);
   }
 
-  private <T> T valueOrDefault(T value, T defaultValue) {
-    return value == null ? defaultValue : value;
-  }
-
-  private String applyNamespace(String base) {
+  public String applyNamespace(String base) {
     if (base == null) return null;
     if (base.contains(".")) return base;
     return namespace + "." + base;
   }
 
+  private <T> T valueOrDefault(T value, T defaultValue) {
+    return value == null ? defaultValue : value;
+  }
+
   private void setStatementCache(
       boolean isSelect,
       boolean flushCache,

Modified: 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLMapperConfigParser.java
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLMapperConfigParser.java?rev=773245&r1=773244&r2=773245&view=diff
==============================================================================
--- 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLMapperConfigParser.java
 (original)
+++ 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLMapperConfigParser.java
 Sat May  9 16:35:37 2009
@@ -18,8 +18,8 @@
 
   private boolean parsed;
 
-  protected Reader reader;
-  protected NodeletParser parser;
+  private Reader reader;
+  private NodeletParser parser;
 
   private String environment;
   private Environment.Builder environmentBuilder;

Modified: 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLMapperParser.java
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLMapperParser.java?rev=773245&r1=773244&r2=773245&view=diff
==============================================================================
--- 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLMapperParser.java
 (original)
+++ 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLMapperParser.java
 Sat May  9 16:35:37 2009
@@ -10,9 +10,11 @@
 
 public class XMLMapperParser extends BaseParser {
 
-  protected Reader reader;
-  protected NodeletParser parser;
-  protected SequentialMapperBuilder sequentialBuilder;
+  private Reader reader;
+  private NodeletParser parser;
+  private SequentialMapperBuilder sequentialBuilder;
+
+  private Map<String,NodeletContext> sqlFragments = new 
HashMap<String,NodeletContext>();
 
   public XMLMapperParser(Reader reader, Configuration configuration, String 
resource, String namespace) {
     this(reader, configuration, resource);
@@ -198,6 +200,14 @@
     sequentialBuilder.resultMapEnd();
   }
 
+  //  <sql id="">
+  @Nodelet("/mapper/sql")
+  public void sqlElement(NodeletContext context) throws Exception {
+    String id = context.getStringAttribute("id");
+
+    sqlFragments.put(id, context);
+  }
+
   //  <select ...>
   @Nodelet("/mapper/select")
   public void selectElement(NodeletContext context) throws Exception {
@@ -222,8 +232,12 @@
     buildStatementFromContext(context);
   }
 
+  public NodeletContext getSqlFragment(String refid) {
+    return sqlFragments.get(refid);
+  }
+
   private void buildStatementFromContext(NodeletContext context) {
-    final XMLStatementParser statementParser = new 
XMLStatementParser(configuration, sequentialBuilder);
+    final XMLStatementParser statementParser = new 
XMLStatementParser(configuration, sequentialBuilder, this);
     statementParser.parseStatementNode(context);
   }
 

Modified: 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLStatementParser.java
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLStatementParser.java?rev=773245&r1=773244&r2=773245&view=diff
==============================================================================
--- 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLStatementParser.java
 (original)
+++ 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLStatementParser.java
 Sat May  9 16:35:37 2009
@@ -1,16 +1,32 @@
 package org.apache.ibatis.parser.xml;
 
+import org.apache.ibatis.mapping.Configuration;
+import org.apache.ibatis.mapping.ResultSetType;
+import org.apache.ibatis.mapping.SqlSource;
+import org.apache.ibatis.mapping.StatementType;
+import org.apache.ibatis.parser.BaseParser;
+import org.apache.ibatis.parser.ParserException;
+import org.apache.ibatis.parser.SequentialMapperBuilder;
+import org.apache.ibatis.parser.SqlSourceParser;
+import org.apache.ibatis.parser.xml.dynamic.*;
 import org.apache.ibatis.xml.NodeletContext;
-import org.apache.ibatis.mapping.*;
-import org.apache.ibatis.parser.*;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 public class XMLStatementParser extends BaseParser {
 
-  protected SequentialMapperBuilder sequentialBuilder;
+  private SequentialMapperBuilder sequentialBuilder;
+  private XMLMapperParser xmlMapperParser;
 
-  public XMLStatementParser(Configuration configuration, 
SequentialMapperBuilder sequentialBuilder) {
+  public XMLStatementParser(Configuration configuration, 
SequentialMapperBuilder sequentialBuilder, XMLMapperParser xmlMapperParser) {
     super(configuration);
     this.sequentialBuilder = sequentialBuilder;
+    this.xmlMapperParser = xmlMapperParser;
   }
 
   public void parseStatementNode(NodeletContext context) {
@@ -35,6 +51,159 @@
         resultMap, resultTypeClass, resultSetTypeEnum, isSelect, flushCache, 
useCache, statementType);
   }
 
-  
+
+  private List<SqlNode> parseDynamicTags(NodeletContext node) {
+    List<SqlNode> contents = new ArrayList<SqlNode>();
+    NodeList children = node.getNode().getChildNodes();
+    for (int i = 0; i < children.getLength(); i++) {
+      NodeletContext child = new NodeletContext(children.item(i), 
configuration.getVariables());
+      String nodeName = child.getNode().getNodeName();
+      if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE
+          || child.getNode().getNodeType() == Node.TEXT_NODE) {
+        String data = child.getStringBody("");
+        contents.add(new TextSqlNode(data));
+      } else {
+        NodeHandler handler = nodeHandlers.get(nodeName);
+        if (handler == null) {
+          throw new ParserException("Unknown element <" + nodeName + "> in SQL 
statement.");
+        }
+        handler.handleNode(child, contents);
+
+      }
+    }
+    return contents;
+  }
+
+  private Map<String, NodeHandler> nodeHandlers = new HashMap<String, 
NodeHandler>() {
+    {
+      put("include", new IncludeNodeHandler());
+      put("prefix", new PrefixHandler());
+      put("where", new WhereHandler());
+      put("set", new SetHandler());
+      put("foreach", new ForEachHandler());
+      put("if", new IfHandler());
+      put("choose", new ChooseHandler());
+      put("when", new IfHandler());
+      put("otherwise", new OtherwiseHandler());
+    }
+  };
+
+  private interface NodeHandler {
+    void handleNode(NodeletContext nodeToHandle, List<SqlNode> targetContents);
+  }
+
+  private class IncludeNodeHandler implements NodeHandler {
+    public void handleNode(NodeletContext nodeToHandle, List<SqlNode> 
targetContents) {
+      String refid = nodeToHandle.getStringAttribute("refid");
+      NodeletContext includeNode = xmlMapperParser.getSqlFragment(refid);
+      if (includeNode == null) {
+        String nsrefid = sequentialBuilder.applyNamespace(refid);
+        includeNode = xmlMapperParser.getSqlFragment(nsrefid);
+        if (includeNode == null) {
+          throw new RuntimeException("Could not find SQL statement to include 
with refid '" + refid + "'");
+        }
+      }
+      MixedSqlNode mixedSqlNode = new MixedSqlNode(contents(includeNode));
+      targetContents.add(mixedSqlNode);
+    }
+
+    private List<SqlNode> contents(NodeletContext includeNode) {
+      return parseDynamicTags(includeNode);
+    }
+  }
+
+  private class PrefixHandler implements NodeHandler {
+    public void handleNode(NodeletContext nodeToHandle, List<SqlNode> 
targetContents) {
+      List<SqlNode> contents = parseDynamicTags(nodeToHandle);
+      MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);
+      String with = nodeToHandle.getStringAttribute("with");
+      String overrides = nodeToHandle.getStringAttribute("overrides");
+      PrefixSqlNode prefix = new PrefixSqlNode(mixedSqlNode, with, overrides);
+      targetContents.add(prefix);
+    }
+  }
+
+  private class WhereHandler implements NodeHandler {
+    public void handleNode(NodeletContext nodeToHandle, List<SqlNode> 
targetContents) {
+      List<SqlNode> contents = parseDynamicTags(nodeToHandle);
+      MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);
+      WhereSqlNode where = new WhereSqlNode(mixedSqlNode);
+      targetContents.add(where);
+    }
+  }
+
+  private class SetHandler implements NodeHandler {
+    public void handleNode(NodeletContext nodeToHandle, List<SqlNode> 
targetContents) {
+      List<SqlNode> contents = parseDynamicTags(nodeToHandle);
+      MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);
+      SetSqlNode set = new SetSqlNode(mixedSqlNode);
+      targetContents.add(set);
+    }
+  }
+
+  private class ForEachHandler implements NodeHandler {
+    public void handleNode(NodeletContext nodeToHandle, List<SqlNode> 
targetContents) {
+      List<SqlNode> contents = parseDynamicTags(nodeToHandle);
+      MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);
+      String collection = nodeToHandle.getStringAttribute("collection");
+      String item = nodeToHandle.getStringAttribute("item");
+      String index = nodeToHandle.getStringAttribute("index");
+      String open = nodeToHandle.getStringAttribute("open");
+      String close = nodeToHandle.getStringAttribute("close");
+      String separator = nodeToHandle.getStringAttribute("separator");
+      ForEachSqlNode forEachSqlNode = new ForEachSqlNode(mixedSqlNode, 
collection, index, item, open, close, separator);
+      targetContents.add(forEachSqlNode);
+    }
+  }
+
+  private class IfHandler implements NodeHandler {
+    public void handleNode(NodeletContext nodeToHandle, List<SqlNode> 
targetContents) {
+      List<SqlNode> contents = parseDynamicTags(nodeToHandle);
+      MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);
+      String test = nodeToHandle.getStringAttribute("test");
+      IfSqlNode ifSqlNode = new IfSqlNode(mixedSqlNode, test);
+      targetContents.add(ifSqlNode);
+    }
+  }
+
+  private class OtherwiseHandler implements NodeHandler {
+    public void handleNode(NodeletContext nodeToHandle, List<SqlNode> 
targetContents) {
+      List<SqlNode> contents = parseDynamicTags(nodeToHandle);
+      MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);
+      targetContents.add(mixedSqlNode);
+    }
+  }
+
+  private class ChooseHandler implements NodeHandler {
+    public void handleNode(NodeletContext nodeToHandle, List<SqlNode> 
targetContents) {
+      List whenSqlNodes = new ArrayList<SqlNode>();
+      List<SqlNode> otherwiseSqlNodes = new ArrayList<SqlNode>();
+      handleWhenOtherwiseNodes(nodeToHandle, whenSqlNodes, otherwiseSqlNodes);
+      SqlNode defaultSqlNode = getDefaultSqlNode(otherwiseSqlNodes);
+      ChooseSqlNode forEachSqlNode = new ChooseSqlNode((List<IfSqlNode>) 
whenSqlNodes, defaultSqlNode);
+      targetContents.add(forEachSqlNode);
+    }
+    private void handleWhenOtherwiseNodes(NodeletContext chooseSqlNode, List 
ifSqlNodes, List<SqlNode> defaultSqlNodes) {
+      List<NodeletContext> children = chooseSqlNode.getChildren();
+      for (NodeletContext child : children) {
+        String nodeName = child.getNode().getNodeName();
+        NodeHandler handler = nodeHandlers.get(nodeName);
+        if (handler instanceof IfHandler) {
+          handler.handleNode(child, ifSqlNodes);
+        } else if (handler instanceof OtherwiseHandler) {
+          handler.handleNode(child, defaultSqlNodes);
+        }
+      }
+    }
+    private SqlNode getDefaultSqlNode(List<SqlNode> defaultSqlNodes) {
+      SqlNode defaultSqlNode = null;
+      if (defaultSqlNodes.size() == 1) {
+        defaultSqlNode = defaultSqlNodes.get(0);
+      } else if (defaultSqlNodes.size() > 1) {
+        throw new ParserException("Too many default (otherwise) elements in 
choose statement.");
+      }
+      return defaultSqlNode;
+    }
+  }
 
 }

Modified: ibatis/trunk/java/ibatis-3/version.properties
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/version.properties?rev=773245&r1=773244&r2=773245&view=diff
==============================================================================
--- ibatis/trunk/java/ibatis-3/version.properties (original)
+++ ibatis/trunk/java/ibatis-3/version.properties Sat May  9 16:35:37 2009
@@ -1,5 +1,5 @@
 #Build version info
-#Sat Apr 11 01:46:47 MDT 2009
+#Tue May 05 17:36:19 MDT 2009
 version=3.0.0
-buildDate=2009/04/11 01\:46
-buildNum=150
+buildDate=2009/05/05 17\:36
+buildNum=152


Reply via email to