Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/rxm.git

Revised example code for thorough testing. Simplified element path grammar; adjusted code accordingly. Using divergent list to compare column mapping paths.

Author Dave Jarvis <email>
Date 2015-03-30 23:37:27 GMT-0700
Commit fd45eae67ecb934f6c7ad13c32ec71e9f9d7b4e1
Parent b8d8020
source/java/com/whitemagicsoftware/rxm/DivergentList.java
public class DivergentList<E> extends ArrayList<E> {
/**
+ * Default (empty) constructor.
+ */
+ public DivergentList() {
+ }
+
+ /**
* Constructs a list containing the elements of the
* specified collection, in the order they are returned by the
source/java/com/whitemagicsoftware/rxm/xml/ColumnMapContext.java
@Override
public String getStart() {
- DivergentList<String> list = new DivergentList<String>( elementNames() );
+ DivergentList<String> thisList = listElementNames();
+ DivergentList<String> prevList = listElementNamesPrev();
- //System.out.println( "NEXT: " + getNextContext() );
- //System.out.println( "PREV: " + getPrevContext() );
+ // If there are no common elements with the previous list, then this is
+ // an entirely new list of elements. This logic is tricky:
+ //
+ // 1. diverges(...) returns the last matching index or -1 for no matches;
+ // 2. the last element name in the path must be unique; therefore,
+ // 3. adding 1 produces the starting index into thisList for
+ // appending ,XMLELEMENTs.
+ //
+ // Closing the parentheses is performed in getStop().
+ int diverges = thisList.diverges( prevList ) + 1;
+ StringBuilder sb = createBuffer();
- return String.format( ",%s,%s.%s",
- startElement( path() ),
- getTableName(),
- getColumnText()
- );
+ for( String element : thisList.subList( diverges, thisList.size() ) ) {
+ sb.append( ',' ).append( startElement( element ) );
+ }
+
+ sb.append( String.format( ",%s.%s", getTableName(), getColumnText() ) );
+
+ return sb.toString();
}
+ /**
+ * Closes the opening XMLELEMENT parentheses.
+ *
+ * @return ")" times the number of required closing parentheses.
+ */
@Override
public String getStop() {
- return String.format( "%s%s",
- stopElement( path() ),
- super.getStop()
- );
+ DivergentList<String> thisList = listElementNames();
+ DivergentList<String> nextList = listElementNamesNext();
+
+ // Determine the number of closing parentheses by noting how many
+ // elements the next column mapping (if any) has in common with the
+ // current mapping.
+ return repeat( thisList.size() - thisList.diverges( nextList ) - 1, ')' );
+ }
+
+ /**
+ * Returns a list of element names that can be compared against another
+ * list (to ascertain where the lists diverge).
+ *
+ * @return A non-null, possibly empty, divergent list.
+ */
+ protected DivergentList<String> listElementNames() {
+ DivergentList<String> result = createDivergentList();
+ result.addAll( elementNames() );
+ return result;
+ }
+
+ /**
+ * Helper method.
+ */
+ private DivergentList<String> listElementNames( Context ctx ) {
+ return ctx != null && ctx instanceof ColumnMapContext ?
+ ((ColumnMapContext)ctx).listElementNames() :
+ createDivergentList();
+ }
+
+ /**
+ * Helper method.
+ */
+ private DivergentList<String> listElementNamesNext() {
+ return listElementNames( getNextContext() );
+ }
+
+ /**
+ * Helper method.
+ */
+ private DivergentList<String> listElementNamesPrev() {
+ return listElementNames( getPrevContext() );
}
/**
- * Returns the path from the column map context, rather than using
- * the superclass's table map context.
- *
- * @return The path associated with the column map parser rule.
+ * Returns the list of elements associated with this context. This
+ * is used to obtain the list of element names for the divergent lists.
*/
- protected QueryParser.PathContext path() {
- return getColumnMapContext().path();
+ protected List<QueryParser.ElementContext> element() {
+ return elementPath().element();
}
+ /**
+ * Helper method.
+ */
protected QueryParser.ElementPathContext elementPath() {
return path().elementPath();
}
- protected List<QueryParser.ElementContext> element() {
- return elementPath().element();
+ /**
+ * Returns the path from the column map context, rather than using
+ * the superclass's table map context.
+ *
+ * @return The path associated with the column map parser rule.
+ */
+ protected QueryParser.PathContext path() {
+ return getColumnMapContext().path();
}
}
source/java/com/whitemagicsoftware/rxm/xml/Context.java
package com.whitemagicsoftware.rxm.xml;
+import java.nio.CharBuffer;
+
import java.util.List;
+import com.whitemagicsoftware.rxm.DivergentList;
import com.whitemagicsoftware.rxm.Tree;
import com.whitemagicsoftware.rxm.grammar.QueryParser;
/**
+ * Constructs a wrapper class that provides the ParserRuleContext and
+ * tree for the *Context classes.
+ *
+ * @param payload The parser rule context to wrap in this context.
* @param tableName The name of the table with respect to this context.
*/
public String getStop() {
return ")";
- }
-
- /**
- * Formats the start of the XMLELEMENT call.
- *
- * @param ctx The name assigned to the element.
- *
- * @return The text used for SQL/XML XMLELEMENT calls.
- */
- protected String startElement( QueryParser.PathContext ctx ) {
- QueryParser.ElementPathContext element = ctx.elementPath();
-
- return startElement( element );
- }
-
- protected String startElement( QueryParser.ElementPathContext ctx ) {
- List<QueryParser.ElementContext> elements = ctx.element();
- StringBuilder sb = new StringBuilder( 2048 );
- String sep = "";
-
- for( QueryParser.ElementContext element : elements ) {
- sb.append( sep );
- sb.append( startElement( element.getText() ) );
- sep = ",";
- }
-
- return sb.toString();
}
/**
- * Formats the start of the XMLELEMENT call.
+ * Formats the start of the XMLELEMENT call. This is used by a number
+ * of subclasses to write an XMLELEMENT call.
*
* @param name The name assigned to the element.
*
* @return The text used for SQL/XML XMLELEMENT calls.
*/
protected String startElement( String name ) {
return String.format( "XMLELEMENT(NAME \"%s\"", name );
- }
-
- protected String stopElement( QueryParser.PathContext ctx ) {
- return stopElement( ctx.elementPath() );
}
-
- protected String stopElement( QueryParser.ElementPathContext ctx ) {
- List<QueryParser.ElementContext> elements = ctx.element();
- StringBuilder sb = new StringBuilder( 2048 );
- String sep = "";
-
- for( QueryParser.ElementContext element : elements ) {
- sb.append( sep );
- sep = ")";
- }
- return sb.toString();
+ /**
+ * Returns an empty list of elements.
+ *
+ * @return A non-null, empty divergent list.
+ */
+ protected DivergentList<String> createDivergentList() {
+ return new DivergentList<String>();
}
*
* @param tableName The new table name context (can be null).
+ * @return The new table name or empty string if 'tableName' is null.
*/
public String setTableName( String tableName ) {
protected Context getPrevContext() {
return this.prevContext;
+ }
+
+ protected StringBuilder createBuffer() {
+ return new StringBuilder( 2048 );
+ }
+
+ /**
+ * Creates a string of repeated text that is n characters long.
+ *
+ * @param n The number of characters in the resulting string.
+ * @param ch The character to repeat.
+ * @return A string padded with n characters.
+ */
+ public String repeat( int n, char ch ) {
+ return CharBuffer.allocate( n ).toString().replace( '\0', ch );
}
}
source/java/com/whitemagicsoftware/rxm/xml/QueryBuilder.java
}
+ /**
+ * Allows reusing the instance.
+ */
private void eventsDeregister() {
getProxyParseTreeListener().clear();
}
+ /**
+ * Registers the initial event listeners: SELECT, FROM, and JOIN. The
+ * WHERE clause listener only starts to receive events if the where
+ * clause syntax event is triggered (i.e., the WHERE clause terminator is
+ * encountered).
+ */
private void eventsRegister() {
receiveEvents( this );
receiveEvents( getSelectClause() );
receiveEvents( getFromClause() );
receiveEvents( getJoinClause() );
}
+ /**
+ * Walks the tree and issues the events.
+ */
private void eventsNotify( QueryParser.QueryContext ctx ) {
ParseTreeWalker.DEFAULT.walk( getProxyParseTreeListener(), ctx );
test/people.rxm
.middle_initial2 > name/middle/initial/i2,
.middle_initial3 > name/middle/initial/i3,
-.last_name > name/last,
-.maiden_name > name/last/original/maiden,
-.flag > @flag,
+.last_name > surname,
+.maiden_name > surname/original/maiden,
.gender > gender,
+.flag > @flag,
account > account,
account.person_id +> person.id,
Delta 135 lines added, 66 lines removed, 69-line increase