# -*- coding: utf8 -*-
'''
SQL BASE MODULE
**********************
***  SQL BASE MODULE
**********************
$RCSfile: base.py,v $
$Revision: 875 $
$Author: markus $
$Date: 2008-04-24 02:23:32 +0200 (Do, 24. Apr 2008) $

General SQL class containing functions and templates applying to all SQL

'''


from types import *
from string import replace
from biocase.wrapper.errorclasses import *
import logging
log=logging.getLogger("pywrapper.sql")


# ---------------------------------------------------------------------------        
class sqlBase:
    '''The base query class containing ANSI standard SQL and routines useful for all DBMS.
    They may be replaced by a spezialized, polymorph DB module inheriting this class.
    The class variable "sql" is a dictionary containing the SQL templates for specific purposes.
    Override any of these in your DBmodule to adopt it to your DBMS.
    #1,#2,#x are placeholders for the real data.
    '''
    # SQL SYNTAX TEMPLATES
    # --------------------
    templates={}
    # full reference to an attribute with its table-alias. #1=table, #2=attribute
    templates['attribute'] = '#1.#2'
    # reference to a table alone
    templates['table'] = '#1'
    # represent a numeric value
    templates['number'] = '#1'
    # represent a string value
    templates['string'] = "'#1'"
    # the wildcard character
    templates['wildcard'] = '%'
    # brackets used for grouping statements
    templates['brackets'] = '(#1)'
    # a select statement. #1=select part, #2=from part
    templates['select'] = 'SELECT #1 FROM #2'
    # a select statement. #1=select part, #2=from(+where+orderby) part, #3=limit/top number
    templates['select-limit'] = 'SELECT DISTINCT #1 FROM #2 LIMIT #3'
    # a count function. #1=list of count attributes
    templates['count'] = 'COUNT(#1)'
    # the where clause of a select statement. #1=select+from part, #2=where part
    templates['where'] = '#1 WHERE #2'
    # the order by clause of a select statement. #1=select+from(+where) part, #2=order by part
    templates['order-by'] = '#1 ORDER BY #2'
    # the left-join syntax of a DBMS. #1=table-alias_1, #2=table-alias_2, #3=comparison/logical operator string joining the tables
    templates['join'] = '#1 LEFT JOIN #2 ON #3'
    # the left-join syntax of a DBMS. #1=table-alias_1, #2=table-alias_2, #3=comparison/logical operator string joining the tables
    templates['full-join'] = '#1, #2'
    # syntax to create an alias of a table. #1=real table name, #2=alias name
    templates['alias'] = '#1 AS #2'

    # LOGICAL OPERATORS
    # -----------------
    unaryLOP  = {"not": "NOT"}        
    binaryLOP = {"and": "AND", "or": "OR"}
    
    # COMPARISON OPERATORS
    # --------------------
    unaryCOP    = {'isnull':"IS NULL", 'isnotnull':"IS NOT NULL"}
    binaryCOP   = {'equals':"=", 'notequals':"<>", 'like':"LIKE", 'lessthan':"<", 'lessthanorequals':"<=", 'greaterthan':">", 'greaterthanorequals':">="}
    multipleCOP = {'in':"IN"}
    # only for output. this is the real spelling which is case sensitive.
    COPout    = {'isnull':"isNull", 'isnotnull':"isNotNull", 'equals':"equals", 'notequals':"notEquals", 'like':"like", 'lessthan':"lessThan", 'lessthanorequals':"lessThanOrEquals", 'greaterthan':"greaterThan", 'greaterthanorequals':"greaterThanOrEquals", 'in':"in"}
    
    # ESCAPE CHARACTERS
    # -----------------
    # characters that need to be escaped in SQL
    escape = {}
    escape["'"] = "''"
    
    # FUNCTION TO BE USED IN LIKE EXPRESSIONS ON BOTH SIDES
    # -----------------
    # usefull to implement case insensitive searches in case sensitive DBMS like Oracle
    caseAlteringFunctionForLike = None
    

    # _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    def apply_template(self, template, args):
        '''Replaces the given template with the passed string arguments. First argument in list will replace #1 and so on.'''
        template = self.__class__.templates[template]
        for i in range(len(args)):
            old = "#%s" %(i+1)
            new = args[i]
            if new == None:
                new = ''
            try:
                new = unicode(new)
            except:
                raise UnicodeError()
            if type(new) not in (StringType, UnicodeType):
                raise unknownType(type(new)    )
            template = replace(template, old, new )
        return template

    # _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    def joinDBAttrObj(self, obj):
        '''create a TABLE.ATTRIBUTE string out of a DBAttributeObject with the help of templates'''
        return self.apply_template('attribute', [obj.table, obj.attr])
    
    # _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    def group_statement(self, statement):
        '''function that applies the grouping template 'brackets' to group a statement.'''
        return self.apply_template('brackets', [statement])

    # _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    def isFalse(self):
        '''Return True is the filter object is False in its evaluation.
        All filters return False except the boolean False.'''
        return False





# ---------------------------------------------------------------------------        
if __name__ ==  "__main__":
    sql = sqlBase()
