############################################################################### ## ## ## ALEXANDRIA DIGITAL LIBRARY ## ## University of California at Santa Barbara ## ## ## ## ------------------------------------------------------------------------- ## ## ## ## Copyright (c) 2003 by the Regents of the University of California ## ## All rights reserved ## ## ## ## Redistribution and use in source and binary forms, with or without ## ## modification, are permitted provided that the following conditions are ## ## met: ## ## ## ## 1. Redistributions of source code must retain the above copyright ## ## notice, this list of conditions, and the following disclaimer. ## ## ## ## 2. Redistributions in binary form must reproduce the above copyright ## ## notice, this list of conditions, and the following disclaimer in ## ## the documentation and/or other materials provided with the ## ## distribution. ## ## ## ## 3. All advertising materials mentioning features or use of this ## ## software must display the following acknowledgement: This product ## ## includes software developed by the Alexandria Digital Library, ## ## University of California at Santa Barbara, and its contributors. ## ## ## ## 4. Neither the name of the University nor the names of its ## ## contributors may be used to endorse or promote products derived ## ## from this software without specific prior written permission. ## ## ## ## THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND ANY ## ## EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ## ## WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE ## ## DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ## ## ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ## ## DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ## ## OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ## ## HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ## ## STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ## ## ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ## ## POSSIBILITY OF SUCH DAMAGE. ## ## ## ############################################################################### # $Header: /export/home/gjanee/bucket99/paradigms/RCS/Temporal_BeginEnd.py,v 1.2 2003/10/23 22:57:35 gjanee Exp $ # SYNOPSIS # # Temporal_BeginEnd (table, idColumn, beginColumn, endColumn, cardinality, # format="ISO 8601", minDate=101, maxDate=99991231) # # table # A table to query, e.g., "holding". # # idColumn # The table's identifier column (i.e., the column to be # selected), e.g., "holding_id". # # beginColumn # The table column that holds begin dates, e.g., "begin". # # endColumn # The table column that holds end dates, e.g., "end". # # cardinality # A Cardinality object representing the cardinality of # 'table' with respect to 'beginColumn' and 'endColumn'. # # format # The format in which dates are written in queries. The # default is "ISO 8601". Currently supported formats are # (using as an example March 5, 1997): # # ISO 8601 # '1997-03-05' # # Oracle # TO_DATE('1997-03-05', 'YYYY-MM-DD') # # minDate # The earliest supported date, expressed as an integer in # the encoding YYYYMMDD. The default value of 101 # corresponds to 0000-01-01, i.e., to January 1, 0000. # Notice that leading zeros have been stripped off to # suppress Python's octal interpretation! # # maxDate # The latest supported date, expressed as an integer in # the encoding YYYYMMDD. The default value of 99991231 # corresponds to December 31, 9999. # # DESCRIPTION # # Translates a temporal constraint to a pair of SQL date # comparisons. This paradigm assumes that a collection item's # temporal footprint is described by a begin date and an end date. # Returned queries generally have the form: # # SELECT idColumn FROM table # WHERE beginColumn op1 'C.begin' AND endColumn op2 'C.end' # # where 'op1' and 'op2' are relational operators and C.begin and # C.end are the limits of the constraint range, although other # query forms are possible. # # The semantics of the "contains" and "is-contained-in" operators # will generally be correct only if the cardinality is "1" or # "1?". The "0+" and "1+" cardinalities should be used with this # paradigm only if collection items truly have multiple, # equivalent temporal footprints. In particular, this paradigm # does not support temporal footprints that are unions of # multiple, arbitrary time ranges. (In the latter case, the # "contains" operator *is* supported if, for each collection item, # the item's time ranges are not only disjoint but are separated # by at least one day. Support for the "is-contained-in" # operator can be added by wrapping this paradigm in an # Adaptor_TemporalIsContainedInRewriter paradigm.) # # Exceptions thrown: # # begin date precedes earliest supported date # end date follows latest supported date # # AUTHOR # # Greg Janee # gjanee@alexandria.ucsb.edu # # HISTORY # # $Log: Temporal_BeginEnd.py,v $ # Revision 1.2 2003/10/23 22:57:35 gjanee # Added the 'format' argument. Minor documentation change. # # Revision 1.1 2003/01/28 18:23:35 gjanee # Initial revision # import types import edu.ucsb.adl.middleware M = edu.ucsb.adl.middleware import UniversalTranslator UT = UniversalTranslator def _formatDate (date, format): UT.assertType(date, types.IntType) UT.assertType(format, types.StringType) if format == "ISO 8601": return "'%04d-%02d-%02d'" % (date/10000, (date%10000)/100, date%100) elif format == "Oracle": return "TO_DATE('%04d-%02d-%02d', 'YYYY-MM-DD')" %\ (date/10000, (date%10000)/100, date%100) else: UT.unhandledCase() class Temporal_BeginEnd (UT.Paradigm): def __init__ (self, table, idColumn, beginColumn, endColumn, cardinality, format="ISO 8601", minDate=101, maxDate=99991231): UT.assertType(table, types.StringType) UT.assertType(idColumn, types.StringType) UT.assertType(beginColumn, types.StringType) UT.assertType(endColumn, types.StringType) UT.assertType(cardinality, UT.Cardinality) UT.assertType(format, types.StringType) assert format in ["ISO 8601", "Oracle"],\ "unrecognized date format: " + format UT.assertType(minDate, types.IntType) assert minDate >= 101, "invalid minimum date: " + str(minDate) # i.e., '0000-01-01' UT.assertType(maxDate, types.IntType) assert maxDate <= 99991231, "invalid maximum date: " + str(maxDate) assert minDate < maxDate, "invalid date limits" self.table = table self.idColumn = idColumn self.beginColumn = beginColumn self.endColumn = endColumn self.cardinality = cardinality self.format = format self.minDate = minDate self.maxDate = maxDate def translateBucketAtomic (self, constraint, vocabularies): UT.assertType(constraint, M.Query.TemporalConstraint) assert constraint.getOperator() in UT.standardTemporalOperators,\ "unsupported operator: " + constraint.getOperator() if constraint.getBegin() < self.minDate: raise UT.QueryError, "temporal constraint target range begin " +\ "date precedes earliest supported date" if constraint.getEnd() > self.maxDate: raise UT.QueryError, "temporal constraint target range end " +\ "date follows latest supported date" table = UT.TableRef(self.table) if constraint.getBegin() == self.minDate and\ constraint.getOperator() != "contains": if constraint.getEnd() == self.maxDate: return UT.constantTrueQuery(self.table, self.idColumn, self.beginColumn, self.cardinality) e = _formatDate(constraint.getEnd(), self.format) if constraint.getOperator() == "is-contained-in": clause = UT.Expression([table, "." + self.endColumn + " <= " + e]) elif constraint.getOperator() == "overlaps": clause = UT.Expression([table, "." + self.beginColumn +\ " <= " + e]) else: UT.unhandledCase() elif constraint.getEnd() == self.maxDate and\ constraint.getOperator() != "contains": b = _formatDate(constraint.getBegin(), self.format) if constraint.getOperator() == "is-contained-in": clause = UT.Expression([table, "." + self.beginColumn +\ " >= " + b]) elif constraint.getOperator() == "overlaps": clause = UT.Expression([table, "." + self.endColumn + " >= " +\ b]) else: UT.unhandledCase() else: b = _formatDate(constraint.getBegin(), self.format) e = _formatDate(constraint.getEnd(), self.format) if constraint.getOperator() == "contains": clause = UT.Expression([table, "." + self.beginColumn +\ " <= " + b]).combine("AND", UT.Expression([table, "." +\ self.endColumn + " >= " + e])) elif constraint.getOperator() == "is-contained-in": clause = UT.Expression([table, "." + self.beginColumn +\ " >= " + b]).combine("AND", UT.Expression([table, "." +\ self.endColumn + " <= " + e])) elif constraint.getOperator() == "overlaps": clause = UT.Expression([table, "." + self.beginColumn +\ " <= " + e]).combine("AND", UT.Expression([table, "." +\ self.endColumn + " >= " + b])) else: UT.unhandledCase() return UT.Select( [UT.MainFrom(table, self.idColumn, self.cardinality)], clause)