;ò à!{Gc@sñdZdkZdkZdkZdkZdkZydklZWn eZnXye e fWn1e j o%ddjddjf\Z Z nXdk Z dei fd„ƒYZdefd„ƒYZd efd „ƒYZd „ZdS( s0.5.1N(sDateTimeiisNotFoundcBstZRS(N(s__name__s __module__(((sO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pysNotFoundss ForgettercBsñtZdZdZdZdZhZdfZfZe Z e Z hZ fZ hZd„ZeeƒZe Zd„Zd„Zd„Zd „Zd „Zd „Zd „Zd „Zd„Zd„ZeeƒZd„Ze d„Zd„Zd„Zde e e d„Z ee ƒZ e d„Z!ee!ƒZ!d„Z"d„Z#d„Z$e e d„Z%ee%ƒZ%e de e d„Z&ee&ƒZ&e e d„Z'ee'ƒZ'e de d„Z(ee(ƒZ(e e e d „Z)d!„Z*d"„Z+d#„Z,RS($s¦SQL to object database wrapper. Given a welldefined database, by subclassing Forgetter and supplying some attributes, you may wrap your SQL tables into objects that are easier to program with. You must define all fields in the database table that you want to expose, and you may refine the names to suit your object oriented programming style. (ie. customerID -> customer) Objects will be created without loading from database, loading will occur when you try to read or write some of the attributes defined as a SQL field. If you change some attributes the object will be saved to the database by save() or garbage collection. (be aware that GC in Py >= 2.2 is not immediate) If you want to create new objects, just supply them with blank ID-fields, and _nextSequence() will be called to fetch a new ID used for insertion. The rule is one class pr. table, although it is possible to join several table into one class, as long as the identificator is unique. By defining _userClasses you can resolve links to other tables, a field in this table would be an id in another table, ie. another class. In practical use this means that behind attributes pointing to other classes (tables) you will find instances of that class. Short example usage of forgetterobjects: # Process all for user in User.getAllIterator(): # Access attributes print user.name print "Employed at:" # Access the Employed-class/table print user.employed.name, user.employed.address # fire him, setting employed reference to SQL NULL user.employed = None # Retrieve some ID shop = Shop(552) shop.name = 'Corrected name' shop.save() # Save now instead of waiting for garbage collactor # Include SQL where-statements in selections myIDs = User.getAllIDs(("name='soiland'", 'salary > 5')) Requirements: The attributes 'cursor' and '_dbModule' should be set from the outside. The cursor should be DB 2.0 complient, preferably with autocommit turned on. (Transactions are not within the scope of this module yet) Python 2.2 (iterators, methodclasses) i<issidcCs+ydk}|iƒSWn d‚nXdS(Ns=cursor method undefined, no database connection could be made(sdatabasescursor(sclssdatabase((sO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pyscursorÂs  cGst|dƒ o h|_ny‹|ii|ƒ o d‚n|i|\}}|ƒ}|tjo d‚nt i ƒ|}||i jo d‚nt i ƒ}Wn4dj o(t i ||Œ}ti|ƒ}nXt i ƒ}||f|i|<|SdS(Ns_cachesNotFound(shasattrsclss_cacheshas_keysargssrefsupdateds realObjectsNonestimesages_timeoutsobjects__new__sweakref(sclssargssupdatedsages realObjectsref((sO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pys__new__Ðs&       cGs:h|_|iƒ| o|iƒn|i|ƒdS(s Initialize, possibly with a database id. A forgetter with multivalue primary key (ie. _sqlPrimary more than 1 in length), may be initalized by using several parameters to this constructor. Note that the object will not be loaded before you call load().N(sselfs_valuessresetsids_resetIDs_setID(sselfsid((sO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pys__init__ês   cCsÙt|ƒtitifjofy9x2|iD]'}|d}||i |<|d}q,WWqÌt j odt |iƒ‚qÌXnHt |iƒdjo|id}||i |s cCsmy|idƒ\}}Wntj o|i}nX|iƒ}|iƒ}t|i|<|d|SdS(s¶Splits a field from _sqlFields into table, column. Registers the table in cls._tables, and returns a fully qualified table.column (default table: cls._sqlTable)s.N( sfieldssplitstables ValueErrorsclss _sqlTablesstripsNones_tables(sclssfieldstable((sO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pys _checkTablePs   cCsY|iƒt|_t|_t|_h|_x$|iiƒD]}t|i|WdS(sReset all fields, almost like creating a new object. Note: Forgets changes you have made not saved to database! (Remember: Others might reference the object already, expecting something else!) Override this method if you add properties not defined in _sqlFieldsN( sselfs_resetIDsNones_news_updateds_changeds_valuess _sqlFieldsskeyssfield(sselfsfield((sO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pysresetds     cCsa|tj o|iƒ|i|ƒn|i o |iƒo|iƒntiƒ|_ dS(s2Loads from database. Old values will be discarded.N( sidsNonesselfsresets_setIDs_news_validIDs_loadDBstimes_updated(sselfsid((sO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pysloadts  cCsX|ip1|iƒo|ip|io|i|ijo|iƒtSntSdS(s9Saves to database if anything has changed since last loadN(sselfs_news_validIDs_changeds_updateds_saveDBsTruesFalse(sself((sO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pyssave~s > cCsL|idƒ\}|iƒ}|i||iƒƒ|iƒ|iƒdS(s„Marks this object for deletion in the database. The object will then be reset and ready for use again with a new id.sDELETEN( sselfs _prepareSQLssqlscursorscurssexecutes_getIDsclosesreset(sselfscursssql((sO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pysdeleteˆs   sSELECTcCs|iƒ}t|ƒtitifjo |f}n|tjo |i }n|ddfjo3g}g} xU|i iƒD]D\} }|tjp | |jo|i| ƒ| i|ƒqqW| od||i f‚nd} | di| ƒ7} | d7} |iiƒ}| o d‚n| di|ƒ7} gi} |iD]}| d|ƒqP~ } |djo0x-|iD]}| i|i |d ƒq„Wn|o| |7} n| o+| d 7} | d i| ƒ7} | d 7} n|djo|o…| d 7} t|ƒtitifjoAgi} |D]}| |i |ƒq<~ }di|ƒ}n|i |}| |7} n| |fSnv|ddfjo¹|djod|i!} nd|i!} g}g}g} x¤|i iƒD]“\} }|djo | |ijoqøn|i#|i!dƒdjoF|t$|i!ƒd}|i| ƒ| i|ƒ|i|d ƒqøqøW|djos| di|ƒ7} | d7} g} x6|iD]+}| i|i |d ƒ|i|ƒqÉW| di| ƒ7} nH| di| ƒ7} | d7} | didft$| ƒƒ7} | d 7} | |fSnª|djo“d|i!d} |o| di|ƒ7} nZxC|iD]8}g} x)|iD]}| i|i |d ƒqÀWqªW| di| ƒ7} | fSn d|‚dS( seReturns a sql for the given operation. Possible operations: SELECT read data for this id SELECTALL read data for all ids INSERT insert data, create new id UPDATE update data for this id DELETE remove data for this id SQL will be built by data from _sqlFields, and will contain 0 or several %s for you to sprintf-format in later: SELECT --> len(cls._sqlPrimary) SELECTALL --> 0 %s INSERT --> len(cls._sqlFields) %s (including id) UPDATE --> len(cls._sqlFields) %s (including id) DELETE --> len(cls._sqlPrimary) (Note: INSERT and UPDATE will only change values in _sqlTable, so the actual number of fields for substitutions might be lower than len(cls._sqlFields) ) For INSERT you should use cls._nextSequence() to retrieve a new 'id' number. Note that if your sequences are not named tablename_primarykey_seq (ie. for table 'blapp' with primary key 'john_id', sequence name blapp_john_id_seq) you must give the sequence name as an optional argument to _nextSequence) Additional note: cls._nextSequence() MUST be overloaded for multi _sqlPrimary classes. Return a tupple. Return values will always be tuples: SELECT --> (sql, fields) SELECTALL -> sql, fields) INSERT -> (sql, fields) UPDATE -> (sql, fields) DELETE -> (sql,) -- for consistency fields will be object properties as a list, ie. the keys from cls._sqlFields. The purpose of this list is to give the programmer an idea of which order the keys are inserted in the SQL, giving help for retreiving (SELECT, SELECTALL) or inserting for %s (INSERT, DELETE). Why? Well, the keys are stored in a hash, and we cannot be sure about the order of hash.keys() from time to time, not even with the same instance. Optional where-parameter applies to SELECT, SELECTALL and DELETE. where should be a list or string of where clauses. sSELECTs SELECTALLsiERROR: No fields defined, cannot create SQL. Maybe sqlPrimary is invalid? Fields asked: %s My fields: %ss SELECT s, s FROM s REALITY ERROR: No tables defineds%s=%ss=%ss WHERE (s ) AND (s)s ORDER BY s, sINSERTsUPDATEsUPDATE %s SET sINSERT INTO %s ( s.iis, s WHERE s AND s ) VALUES ( s%ssDELETEs DELETE FROM s WHERE sUnknown operationN(%s operationsupperstypeswherestypess StringTypes UnicodeTypesorderBysNonesclss_orderBysfieldss sqlfieldss _sqlFieldssitemssfieldssqlfields selectfieldssappendssqlsjoins_tablesskeysstabless_[1]s _sqlLinksslinkPairs tempWheres _sqlPrimaryskeys TupleTypesListTypesxs _sqlTablessetsfindslen(sclss operationswheres selectfieldssorderBystablesssetslinkPairskeys tempWheres sqlfieldss_[1]sfieldssqlsfieldsssqlfieldsx((sO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pys _prepareSQL’sª3        .     .                 cCs¬| o |i}n| oPt|iƒdjo d‚n|id}d|i|iddƒf}n|iƒ}|i d|ƒ|i ƒd}|i ƒ|SdS( s?Returns a new sequence number for insertion in self._sqlTable. Note that if your sequences are not named tablename_primarykey_seq (ie. for table 'blapp' with primary key 'john_id', sequence name blapp_john_id_seq) you must give the full sequence name as an optional argument to _nextSequence) is3Could not guess sequence name for multi-primary-keyis %s_%s_seqs.s_sSELECT nextval('%s')N(snamesclss _sqlSequenceslens _sqlPrimarysprimarys _sqlTablesreplacescursorscurssexecutesfetchonesvaluesclose(sclssnamescurssprimarysvalue((sO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pys _nextSequence.s   #  c CsÜd}xÏ|D]Ç}||}|i|d}t|i dƒo*||i i jo|t j p |t j o|ot pt }n|o|ii|ƒo|i|}||ƒ}n||i|<|d7}q WdS(sµLoad from a database row, described by fields. fields should be the attribute names that will be set. Note that userclasses will be created (but not loaded). iisBOOLEANN(spositionsfieldsselemsresultsvaluescursors descriptions valueTypeshasattrsselfs _dbModulesBOOLEANsTruesFalses _userClassesshas_keys userClasss_values( sselfsresultsfieldsscursorselemsvalues userClassspositions valueType((sO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pys _loadFromRowFs @  cCs¯|iƒ ot|iƒ‚n|idƒ\}}|iƒ}|i ||iƒƒ|i ƒ}|i ƒ| ot|iƒ‚n|i |||ƒtiƒ|_dS(s'Connects to the database to load myselfsSELECTN(sselfs_validIDsNotFounds_getIDs _prepareSQLssqlsfieldsscursorscurssexecutesfetchonesresultscloses _loadFromRowstimes_updated(sselfscurssfieldssresultssql((sO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pys_loadDB\s   cCs¸tiƒ|_|io/d}|iƒ o|i|iƒƒqNnd}|i|ƒ\}}g}x|D]}t ||ƒ}tot|ƒtijot|ƒ}ntot|ƒtijo |idƒt|iƒ}n|tjp |tjo|odpd}nt|tƒoC|io|iƒny|iƒ\}Wqtd|‚qtXn|i|ƒqpW|iƒ}|i||ƒ|iƒt|_dS(smInserts or updates into the database. Note that every field will be updated, not just the changed one.sINSERTsUPDATEs %d %H:%M:stsfs5Unsupported: Can't reference multiple-primary-key: %sN( stimesselfs_updateds_news operations_validIDs_setIDs _nextSequences _prepareSQLssqlsfieldssvaluessfieldsgetattrsvaluesDateTimestypes DateTimeTypesstrsDateTimeDeltaTypesstrftimessecondsTruesFalses isinstances Forgetterssaves_getIDsappendscursorsexecutesclose(sselfsfieldssvaluescursorsfieldsvaluesssqls operation((sO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pys_saveDBjs<      cCs‰|i|d|ƒ}t|iƒdjo/gi}|D]}|||Œƒq9~Sn,gi}|D]}|||ƒƒqh~SdS(sWRetrieves all the objects, possibly matching the where list of clauses, that will be AND-ed. This will not load everything out from the database, but will create a large amount of objects with only the ID inserted. The data will be loaded from the objects when needed by the regular load()-autocall.sorderByiN( sclss getAllIDsswheresorderBysidsslens _sqlPrimarysappends_[1]sid(sclsswheresorderBysidss_[1]sid((sO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pysgetAll s /idc srˆid|d|ƒ\} ‰ˆiƒ‰tiƒ‰ˆi | ƒg‡‡‡‡‡‡d†}t |t ƒSdS(sbRetrieves every object, possibly limitted by the where list of clauses that will be AND-ed). Since this an iterator is returned, only buffer rows are loaded from the database at once. This is useful if you need to process all objects. If useObject is given, this object is returned each time, but with new data. s SELECTALLsorderByc s-ˆ}| o|ˆiˆƒ7}n| oˆiƒtSn|d}|d=y7gi }ˆi D]}|ˆi|ƒƒqd~}Wn tj odˆi ‚nXgi }|D]}|||ƒq¸~}ˆo!ˆ}|iƒ|i|ƒn ||Œ}|i|ˆˆƒˆ|_|SdS(Nis.Bad sqlPrimary, should be a list or tupple: %s(sclss forgettersrowsscurss fetchmanysbuffersclosesNonesrowsappends_[1]s _sqlPrimaryskeysfieldssindexs idPositionss ValueErrorspossidss useObjectsresultsresets_setIDs _loadFromRows fetchedAts_updated( srowss forgettersidss_[1]spossresultskeys idPositionssrow(scurssbuffersfieldss fetchedAts useObjectscls(sO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pysgetNextÂs*  7+   N(sclss _prepareSQLswheresorderByssqlsfieldsscursorscursstimes fetchedAtsexecutesgetNextsitersNone( sclsswheresbuffers useObjectsorderBysgetNexts fetchedAtscurssfieldsssql((sclssbuffers useObjects fetchedAtsfieldsscurssO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pysgetAllIterator²s   cCs |id||id|ƒ\} }|iƒ}|i | ƒ|i ƒ}|i ƒg} gi}|iD]} ||i| ƒƒqj~} xs|D]k} gi}| D]}|| |ƒq§~}t| ƒdjot|ƒ}n |d}| i|ƒq“W| SdS(sòRetrives all the IDs, possibly matching the where clauses. Where should be some list of where clauses that will be joined with AND). Note that the result might be tuples if this table has a multivalue _sqlPrimary.s SELECTALLsorderByiiN(sclss _prepareSQLswheres _sqlPrimarysorderByssqlsfieldsscursorscurssexecutesfetchallsrowssclosesresultsappends_[1]skeysindexs idPositionssrowspossidsslenstuple(sclsswheresorderBysrowsscurssfieldssidssposs_[1]sresultskeyssqls idPositionssrow((sO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pys getAllIDsÞs"     3+ s cCsw|id|d|ƒ\}}|iƒ}|i|ƒ|i ƒ}|i ƒg} gi } |iD]}| |i|ƒƒqd~ }gi } |iD]} | |i| ƒƒq—~ }x³|D]«}gi } |D]} | || ƒqÔ~ }t|ƒdjot|ƒ}n |d}|igi } |D]} | t|| ƒƒq2~ ƒ} | i || fƒqÀW| SdS(sñRetrieves a list of of all possible instances of this class. The list is composed of tupples in the format (id, description) - where description is a string composed by the fields from cls._shortView, joint with SEPERATOR. s SELECTALLsorderByiiN(sclss _prepareSQLswheresorderByssqlsfieldsscursorscurssexecutesfetchallsrowssclosesresultsappends_[1]s _sqlPrimaryskeysindexs idPositionss _shortViewsshortsshortPossrowspossidsslenstuples SEPERATORsjoinsstrstext(sclsswheres SEPERATORsorderBysshortPossrowsscurssfieldssidssposs_[1]sshortstextsresultskeyssqls idPositionssrow((sO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pys getAllTextùs$    33+ :c Csät|ƒtitifjo |f}n| o?x<|iiƒD]'\}}t ||ƒo |}PqDqDWn| o d‚n|i |} |iƒd}d| |fg}|o|i|ƒn|i|d|ƒSdS(sReturns the children that links to me. That means that I have to be listed in their _userClasses somehow. If field is specified, that field in my children is used as the pointer to me. Use this if you have multiple fields referring to my class.s.No field found, check forgetter's _userClassesis%s='%s'sorderByN(stypeswherestypess StringTypes UnicodeTypesfields forgetters _userClassessitemssi_fieldsi_classs isinstancesselfs _sqlFieldsssqlnames_getIDsmyIDs whereListsextendsgetAllsorderBy( sselfs forgettersfieldswheresorderBysi_fields whereListsi_classsmyIDssqlname((sO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pys getChildrens"     cCs|iid|iƒSdS(Ns %s(sselfs __class__s__name__s_getID(sself((sO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pys__repr__.scCs`|ip|i}gi}|D]}|tt||ƒƒƒq!~}di |ƒ}|SdS(Ns, ( sselfs _shortViews _sqlPrimarys shortViewsappends_[1]sshortsstrsgetattrsjoinstext(sselfs shortViewsshortstexts_[1]((sO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pys__str__1s6cCs3|ii|iijo|iƒ|iƒjSdS(sSimple comparsion of objects.N(sselfs __class__s__name__sobjs_getID(sselfsobj((sO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pys__eq__8s(-s__name__s __module__s__doc__s_timeouts _prepareds _sqlTables _sqlFieldss _sqlPrimarys _sqlLinkssNones _sqlSequences_orderBys _userClassess _shortViews _descriptionsscursors classmethods _dbModules__new__s__init__s_setIDs_getIDs_resetIDs_validIDs __getattr__s __setattr__s__del__s _checkTablesresetsloadssavesdeletes _prepareSQLs _nextSequences _loadFromRows_loadDBs_saveDBsgetAllsgetAllIterators getAllIDss getAllTexts getChildrens__repr__s__str__s__eq__(((sO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pys Forgetter sb :               š      6 *     sMysqlForgettercBstZdZd„ZRS(sMYSQL-compatible ForgettercCs@tiƒ|_|io d}nd}|i|ƒ\}}g}x}|D]u}t ||ƒ}t |t ƒoC|io|iƒny|iƒ\}Wq³d|‚q³Xn|i|ƒqKW|iƒ}|i||ƒ|iƒ o;t|iƒƒdj o d‚n|i|iƒƒn|iƒt|_dS(s,Overloaded - we dont have nextval() in mysqlsINSERTsUPDATEs(Can't reference multiple-primary-key: %sis8Can't retrieve auto-inserted ID for multiple-primary-keyN(stimesselfs_updateds_news operations _prepareSQLssqlsfieldssvaluessfieldsgetattrsvalues isinstances Forgetterssaves_getIDsappendscursorsexecutes_validIDslens_setIDs insert_idsclosesFalse(sselfsfieldssvaluescursorsfieldsvaluesssqls operation((sO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pys_saveDB@s4      (s__name__s __module__s__doc__s_saveDB(((sO/mnt/gmirror/ports/databases/py-forgetsql/work/forgetSQL-0.5.1/lib/forgetSQL.pysMysqlForgetter>s c CsHxA|iƒD]3\}}t|ƒtijo t|tƒ oq nxN|i iƒD]=\}} t| ƒti jo|| }||i |