Class NXQLQueryMaker

java.lang.Object
org.nuxeo.ecm.core.storage.sql.jdbc.NXQLQueryMaker
All Implemented Interfaces:
QueryMaker
Direct Known Subclasses:
TagQueryMaker

public class NXQLQueryMaker extends Object implements QueryMaker
Transformer of NXQL queries into underlying SQL queries to the actual database.

The examples below are using the NXQL statement syntax:

 SELECT * FROM File
 WHERE
   dc:title = 'abc'
   AND uid:uid = '123'
   AND dc:contributors = 'bob'    -- multi-valued
 
If there are no proxies (ecm:isProxy = 0) we get:
 SELECT hierarchy.id
   FROM hierarchy
   LEFT JOIN dublincore ON hierarchy.id = dublincore.id
   LEFT JOIN uid ON hierarchy.id = uid.id
 WHERE
   hierarchy.primarytype IN ('File', 'SubFile')
   AND dublincore.title = 'abc'
   AND uid.uid = '123'
   AND EXISTS (SELECT 1 FROM dc_contributors WHERE hierarchy.id = dc_contributors.id
               AND dc_contributors.item = 'bob')
   AND NX_ACCESS_ALLOWED(hierarchy.id, 'user1|user2', 'perm1|perm2')
 
The data tables (dublincore, uid) are joined using a LEFT JOIN, as the schema may not be present on all documents but this shouldn't prevent the WHERE clause from being evaluated. Complex properties are matched using an EXISTS and a subselect. When proxies are matched (ecm:isProxy = 1) there are two additional FULL JOINs. Security checks, id, name, parents and path use the base hierarchy (_H), but all other data use the joined hierarchy.
 SELECT _H.id
   FROM hierarchy _H
   JOIN proxies ON _H.id = proxies.id                     -- proxy full join
   JOIN hierarchy ON hierarchy.id = proxies.targetid      -- proxy full join
   LEFT JOIN dublincore ON hierarchy.id = dublincore.id
   LEFT JOIN uid ON hierarchy.id = uid.id
 WHERE
   hierarchy.primarytype IN ('File', 'SubFile')
   AND dublincore.title = 'abc'
   AND uid.uid = '123'
   AND EXISTS (SELECT 1 FROM dc_contributors WHERE hierarchy.id = dc_contributors.id
               AND dc_contributors.item = 'bob')
   AND NX_ACCESS_ALLOWED(_H.id, 'user1|user2', 'perm1|perm2') -- uses _H
 
When both normal documents and proxies are matched, we UNION ALL the two queries. If an ORDER BY is requested, then columns from the inner SELECTs have to be aliased so that an outer ORDER BY can user their names.
Author:
Florent Guillaume
  • Field Details

  • Constructor Details

    • NXQLQueryMaker

      public NXQLQueryMaker()
  • Method Details

    • getName

      public String getName()
      Description copied from interface: QueryMaker
      Gets the name for this query maker.
      Specified by:
      getName in interface QueryMaker
    • accepts

      public boolean accepts(String queryType)
      Description copied from interface: QueryMaker
      Checks if this query maker accepts a given query.

      Called first.

      Specified by:
      accepts in interface QueryMaker
      Parameters:
      queryType - the query
      Returns:
      true if the query is accepted
    • buildQuery

      public QueryMaker.Query buildQuery(SQLInfo sqlInfo, Model model, Session.PathResolver pathResolver, String query, QueryFilter queryFilter, Object... params)
      Description copied from interface: QueryMaker
      Builds the query.
      Specified by:
      buildQuery in interface QueryMaker
      Parameters:
      sqlInfo - the sql info
      model - the model
      pathResolver - the path resolver
      query - the query
      queryFilter - the query filter
      params - additional parameters, maker-specific
    • addJoin

      protected void addJoin(int kind, String alias, Table table, String column, Table contextTable, String contextColumn, String name, int index, String primaryType)
    • getFragmentTable

      protected Table getFragmentTable(Table contextHier, String fragmentName)
      Gets the table for the given fragmentName, and maybe adds a join if one is not already done.

      LEFT JOIN fragmentName _F123 ON contextHier.id = _F123.id

    • getFragmentTable

      protected Table getFragmentTable(int joinKind, Table contextTable, String contextKey, String fragmentName, String fragmentColumn, int index, boolean skipJoin, String primaryType)
      Adds a more general JOIN:

      (LEFT) JOIN fragmentName _F123 ON contextTable.id = _F123.fragmentColumn

    • fixInitialJoins

      protected void fixInitialJoins()
    • getSelectColName

      protected String getSelectColName(Column col)
    • getSelectColName

      protected String getSelectColName(Column col, String key)
      key used to extract array index if needed
    • fixWhatColumns

      protected void fixWhatColumns(List<Column> whatColumns)
    • fixSelect

      protected void fixSelect(Select select)
    • findFulltextIndexOrField

      protected static boolean findFulltextIndexOrField(Model model, String[] nameref)
    • canonicalXPath

      public static String canonicalXPath(String xpath)
      Canonicalizes a Nuxeo-xpath.

      Replaces a/foo[123]/b with a/123/b

      A star or a star followed by digits can be used instead of just the digits as well.

      Parameters:
      xpath - the xpath
      Returns:
      the canonicalized xpath.
    • simpleXPath

      public static String simpleXPath(String xpath)
      Turns the xpath into one where all indices have been replaced by *.
      Parameters:
      xpath - the xpath
      Returns:
      the simple xpath
    • hasWildcardIndex

      public boolean hasWildcardIndex(String xpath)
    • hasFinalWildcardIndex

      public boolean hasFinalWildcardIndex(String xpath)
    • keyForPos

      protected static String keyForPos(String name)
    • newQueryAnalyzer

      protected NXQLQueryMaker.QueryAnalyzer newQueryAnalyzer(FacetFilter facetFilter)
    • getStringLiterals

      protected static Set<String> getStringLiterals(LiteralList list)
    • getSerializableLiteral

      protected static Serializable getSerializableLiteral(Literal literal)
    • getSerializableLiterals

      protected static List<Serializable> getSerializableLiterals(LiteralList list)
    • newWhereBuilder

      protected NXQLQueryMaker.WhereBuilder newWhereBuilder(boolean isProxies)