query_catalog.py 10.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
##############################################################################
#
# Copyright (c) 2002-2009 Nexedi SA and Contributors. All Rights Reserved.
#                    Jean-Paul Smets-Solanes <jp@nexedi.com>
#                    Vincent Pelletier <vincent@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
##############################################################################

30
from zope.interface import Interface
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57

class ISearchKeyCatalog(Interface):

  def buildQuery(kw, ignore_empty_string=True, operator='and'):
    """
      Build a ComplexQuery from kw values.

      kw (dict: string keys, any value)
        A query will be emited based on its value. Depending on the type of
        the value it is handled differently. Query values will be passed
        through to result (key is ignored). For all other types, their key
        must be either a known column of a sql_search_tables table, or a
        related key name.
        - String values will be parsed according to the default SearchKey of
          their real column (even for related keys). If parsing was
          successful, Queries will be generated from its output.
          Otherwise, that value will be taken as such.
        - Dictionary values can be composed of the following keys:
          'query': Their payload value, considered as empty if not given.
          'key': The SearchKey to use for this value, overriding default
                 column configuration.
          (for other possible keys, see SearchKeys)
          They will be taken as such.
        - All other types will be taken as such, and no "empty" check will be
          performed on them.
      ignore_empty_string (boolean)
        If True, values from kw which are empty will be skipped.
58 59 60
        This parameter should ultimately disapear *and* be disabled by
        default, as it is bad to ignore parameters based on their value if
        that value has a meaning in SQL.
61 62 63 64 65
      operator (string)
        Used to explicit the logical relation between kw entries.
        It must be a valid ComplexQuery logical operator ('and', 'or').
    """

66 67
  def buildEntireQuery(kw, query_table='catalog', ignore_empty_string=1,
                       limit=None, extra_column_list=None):
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
    """
      Construct and return an instance of EntireQuery class from given
      parameters by calling buildQuery.

      ignore_empty_string (boolean)
        See buildQuery.
      limit (1-tuple, 2-tuple)
        If given, will emit SQL to limit the number of result lines.
      group_by_list (list of strings)
        If given, will emit SQL to group found lines on given parameter names
        (their column if they are column names, corresponding virtual columns
        otherwise - as for related keys).
      select_dict (dict, key: string, value: string, None)
        Given values describe columns to make available in SQL result.
        If column is aliased in result set, key is the alias and value is the
        column.
        Otherwise, key is the column, and value can be None or the same as
        key.
      select_list (list of strings)
        Same as providing select_dict with select_list items as keys, and None
        values.
      order_by_list (list of 1-, 2-, or 3-tuples of strings)
        If given, will emit SQL to sort result lines.
        Sort will happen with decreasing precedence in list order.
        Given n-tuples can contain those values, always in this order:
         - parameter name
         - sort order (see SQL documentation of 'ORDER BY')
         - type cast (see SQL documentation of 'CAST')
        Sort will happen on given parameter name (its column if it's a column
        name, corresponding virtual column otherwise - as for related keys).
      Extra parameters are passed through to buildQuery.

      Backward compatibility parameters:
      Those parameters are deprecated and should not be used. They are present
      to provide backward compatibility with former ZSQLCatalog version.
      REQUEST
        Ignored.
      extra_column_list (list)
      query_table (string, None)
        The table to use as catalog table.
        If given and None, not catalog table will be used. Use this when you
        are using SQLCatalog to generate manualy a part of another query.
        That table has a special position in returned query:
         - all other tables are joined on this one (when it is required to use
           other tables)
         - it is expected to have some columns (uid, path)
        It is strongly discouraged to use this parameter for any value other
        than None.
      group_by
        Use group_by_list instead.
      group_by_expression
        Use group_by_list instead.
      select_expression
        Use select_list or select_dict instead.
      sort_on
        Use order_by_list instead.
      sort_order
        Use order_by_list instead.
      from_expression
        This value will be emited in SQL directly in addition to computed
        value.
        There is no replacement.
      where_expression
        This value will be emited in SQL directly in addition to computed
        value.
        Use Query instances instead.
      select_expression_key
        This prevents given column from being ignored even if they could not
        be mapped.
        There is no replacement.
138 139 140 141 142 143 144 145 146 147 148 149 150
    """


  def buildSQLQuery(query_table='catalog', REQUEST=None,
                    ignore_empty_string=1, only_group_columns=False,
                    limit=None, extra_column_list=None,
                    **kw):
    """
      Return an SQLExpression-generated dictionary (see
      SQLExpression.asSQLExpressionDict). That SQLExpression is generated by
      an EntireQuery, itself generated by buildEntireQuery from given
      parameters.

151 152 153
      only_group_columns
        Replaces former stat__ parameter.
        Used to globally disalow use of non-group columns in SQL.
154 155

      For other parameters, see buildEntireQuery.
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
    """

  def getSearchKey(column, search_key=None):
    """
      Returns the default SearchKey instance for the
      requested column. There is one instance per
      search_key (incl. virtual keys surch as
      source_title) and we try to compute it once
      only and cache it.
      If search_key is provided, it is used as the
      name of the search key class to return.
    """

  def getComparisonOperator(operator):
    """
      Return a comparison operator matching given string.
      String must be a valid SQL comparison operator (=, LIKE, IN, ...).
      String case does not matter.
      There is one comparison operator instance per possible string value.
    """

177 178 179 180 181 182
  def hasColumn(column):
    """
      Check if the given column or virtual column (in case
      of related keys) exists or not
    """

183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
  # TODO: add support for other operators (logical, ensemblist (?))

  def searchResults(REQUEST=None, **kw):
    """
      Invokes queryResults with the appropriate
      ZSQL Method to return a list of results
    """

  def countResults(REQUEST=None, **kw):
    """
      Invokes queryResults with the appropriate
      ZSQL Method to return a statistics for
      a list of results
    """

  def queryResults(sql_method, REQUEST=None, src__=0, build_sql_query_method=None, **kw):
    """
      Return the result of the given 'sql_method' ZSQL Method after
      processing all parameters to build a Query object passed to
      that method.

      The implementation should do the following.

      1- Use **kw parameters to build a Query object
         by invoking buildQuery

      2- Build a ColumnMap instance by invoking
         the buildColumnMap on the Query. Some
         optmisation may happen here to try
         to build the best possible ColumnMap and
         use the best possible indices for joining.
         During the ColumnMap build process, the
         Search Key associated to each Query node
         in the Query tree registers the columns
         which are used (ex. to search) or provided
         (ex. MATCH value for full text search, 
         interleave expression or parameter in a
         UNION Query)

      3- Render the query object as an SQLExpression
         instance. This instance contains all necessary
         parts to generate:
           - where_expression
           - sort_expression
           - group_by_expression
           - select_expression

      4- Invoke sql_method
    """
232 233 234 235 236 237 238

  def isAdvancedSearchText(search_text):
    """
      Returns True if given value follows Search Text "advanced" syntax,
      False otherwise.
    """

239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
  def parseSearchText(search_text, column=None, search_key=None, is_valid=None):
    """
      Parses given SearchText expression using given column's parser
      (determined by the SearchKey it is configured to use by default), or
      given SearchKey name.

      search_text (string)
        SearchText to parse.
      column (string)
        Column to use to determine which SearchKey to use for parsing.
        Either this parameter or search_key must be provided.
      search_key (string)
        Name of the SearchKey to use for parsing.
        Either this parameter or column must be provided.
      if_valid (callback)
        Callback method to use to decide wether an encountered column-ish
        identifier in SearchText is a valid column.
        If not provided, catalog schema will be used.
    """