############################################################################### ## ## ## 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/Adaptor_Relationship.py,v 1.2 2003/10/28 22:28:06 gjanee Exp $ # SYNOPSIS # # Adaptor_Relationship (table, idColumn, joinColumn, cardinality, # paradigm) # # table # A main table to query, e.g., "item". # # idColumn # The table's item identifier column (i.e., the column to # be selected), e.g., "item_id". # # joinColumn # The column to INNER JOIN on, e.g., "author_id". # # cardinality # A Cardinality object representing the overall # cardinality of the combined expression. # # paradigm # The underlying paradigm. # # DESCRIPTION # # Adds an inner equijoin relationship to queries returned by an # underlying paradigm. This adaptor is useful in situations in # which a bucket is implemented by placing a constraint against a # database entity that has an indirect relationship to collection # items. # # For example, consider a schema with 'item' and 'author' tables # representing collection items and item authors, respectively, # and an 'authorship' table that represents the many-to-many # relationship between collection items and item authors. # # CREATE TABLE item ( # item_id INTEGER NOT NULL, # ..., # PRIMARY KEY (item_id) # ); # # CREATE TABLE authorship ( # item_id INTEGER NOT NULL, # author_id INTEGER NOT NULL, # FOREIGN KEY (item_id) REFERENCES item, # FOREIGN KEY (author_id) REFERENCES author # ); # # CREATE TABLE author ( # author_id INTEGER NOT NULL, # ..., # PRIMARY KEY (author_id) # ); # # A bucket for authors of collection items can be expressed by # defining a paradigm for authors, and then relating authors to # collection items, as in: # # P.Adaptor_Relationship( # "authorship", # "item_id", # "author_id", # UT.Cardinality("1+"), # P.some_underlying_paradigm("author", "author_id", ...)) # # The underlying paradigm must return, given an appropriate atomic # bucket-level constraint, a Select object that queries exactly # one main table, i.e., a SELECT statement of the form: # # SELECT underlyingIdColumn FROM underlyingMainTable, ... # WHERE condition # # This adaptor transforms the above into: # # SELECT idColumn FROM table, underlyingMainTable, ... # WHERE table.joinColumn = # underlyingMainTable.underlyingIdColumn AND # condition # # The cardinality of 'underlyingMainTable' is ignored. # # Exceptions thrown: # # none # # AUTHOR # # Greg Janee # gjanee@alexandria.ucsb.edu # # HISTORY # # $Log: Adaptor_Relationship.py,v $ # Revision 1.2 2003/10/28 22:28:06 gjanee # Removed the field-level methods to conform to the new # field translation strategy introduced in revision 1.8 of # UniversalTranslator.py. # # Revision 1.1 2003/01/24 22:16:29 gjanee # Initial revision # import types import UniversalTranslator UT = UniversalTranslator class Adaptor_Relationship (UT.Paradigm): def __init__ (self, table, idColumn, joinColumn, cardinality, paradigm): UT.assertType(table, types.StringType) UT.assertType(idColumn, types.StringType) UT.assertType(joinColumn, types.StringType) UT.assertType(cardinality, UT.Cardinality) UT.assertType(paradigm, UT.Paradigm) self.table = table self.idColumn = idColumn self.joinColumn = joinColumn self.cardinality = cardinality self.paradigm = paradigm def _process (self, query): UT.assertType(query, UT.Select) froms = query.froms + [] mainFrom = None i = 0 for f in froms: if isinstance(f, UT.MainFrom): assert mainFrom == None, "multiple main tables" mainFrom = f mainFromIndex = i i += 1 assert mainFrom != None, "no main table" table = UT.TableRef(self.table) froms[mainFromIndex] = UT.AuxiliaryFrom(mainFrom.table, UT.Expression([table, "." + self.joinColumn + " = ", mainFrom.table, "." + mainFrom.joinableIdColumn()])) return UT.Select( [UT.MainFrom(table, self.idColumn, self.cardinality)] + froms, query.expression) def translateBucketAtomic (self, constraint, vocabularies): return self._process( self.paradigm.translateBucketAtomic(constraint, vocabularies)) def translateBucketBoolean (self, operator, constraints, vocabularies): query = self.paradigm.translateBucketBoolean(operator, constraints, vocabularies) if isinstance(query, types.NoneType) or isinstance(query, UT.Query): return None else: UT.assertType(query, UT.Select) i = 0 for f in query.froms: if isinstance(f, UT.MainFrom): i += 1 if i <= 1: return self._process(query) else: return None