U kf@sdZddlmZddlmZddlmZddlmZddlmZddlmZ dd l m Z dd l m Z dd l m Z d dlmZd d lmZd dlmZGdddZGdddeZGdddeZGdddeZGdddeZe ee ee eiZdS)zRelationship dependencies. ) annotations) attributes)exc)sync) unitofwork)util) MANYTOMANY) MANYTOONE) ONETOMANY)sqlc@seZdZddZeddZddZddZd d Zd d Z d dZ ddZ ddZ ddZ ddZddZddZddZd%ddZd d!Zd"d#Zd$S)&DependencyProcessorcCs||_|j|_|j|_|j|_|j|_|j|_|j|_|j|_|j|_|j |_ |jr^t j |_ nt j |_ |jrvt j |_nt j |_d|jj|jf|_|j|_|jjstd|jdS)Nz%s_%sz|Can't build a DependencyProcessor for relationship %s. No target attributes to populate between parent and child are present)propcascademapperparent secondary direction post_updatepassive_deletespassive_updatesenable_typechecksrPASSIVE_NO_INITIALIZE_passive_delete_flag PASSIVE_OFF_passive_update_flag _sort_keykeysort_keysynchronize_pairssa_exc ArgumentError)selfrr$I/opt/hc_python/lib64/python3.8/site-packages/sqlalchemy/orm/dependency.py__init__s0  zDependencyProcessor.__init__cCst|j|SN)_direction_to_processorr)clsrr$r$r%from_relationship;sz%DependencyProcessor.from_relationshipcCs|jj|j|S)zreturn True if the given object instance has a parent, according to the ``InstrumentedAttribute`` handled by this ``DependencyProcessor``. )rZ class_managerget_implr hasparentr#stater$r$r%r,?szDependencyProcessor.hasparentcCs||ddS)zestablish actions and dependencies related to a flush. These actions will operate on all relevant states in the aggregate. TN)register_preprocessorr#uowr$r$r%per_property_preprocessorsGsz.DependencyProcessor.per_property_preprocessorsc Cszt||dd}t||dd}t||jj}t||jj}t||jj}t||jj}||||||||dSNFT)r ProcessAll SaveUpdateAllrprimary_base_mapperr DeleteAllper_property_dependencies)r#r1 after_save before_delete parent_saves child_savesparent_deletes child_deletesr$r$r%per_property_flush_actionsPs6z.DependencyProcessor.per_property_flush_actionsc Cs|jj}t||}t||}|rr:r9Z child_actionsZchild_in_cyclesr;r=Zparent_in_cyclesr.Zsum_Z child_statechild child_actiondeletedZlistonly childisdeleter$r$r%per_state_flush_actionsls              z+DependencyProcessor.per_state_flush_actionscCsdSNFr$r# uowcommitrFr$r$r%presort_deletessz#DependencyProcessor.presort_deletescCsdSrOr$rPr$r$r% presort_savessz!DependencyProcessor.presort_savescCsdSr'r$rPr$r$r%process_deletessz#DependencyProcessor.process_deletescCsdSr'r$rPr$r$r% process_savessz!DependencyProcessor.process_savescCs||r |jrtjtjB}n|jtkr*tj}n tjtjB}|D]&}|||j |}|r:| s:dSq:|oz|j j oz|j |jkS)NT)rrrINCLUDE_PENDING_MUTATIONSrr ZPASSIVE_NO_FETCH_RELATEDrget_attribute_historyremptyrZ_is_self_referentialrZmappers)r#rQrFrIpassiveshistoryr$r$r%prop_has_changess$     z$DependencyProcessor.prop_has_changescCs|jjr$|dkr$td|jfnn|dk r|jj||j ds|jj|ddrttd|j|j|jj|jdntd|j|j|jjddS)Nz-Can't flush None value found in collection %s)Zallow_subtypesTaEAttempting to flush an item of type %(x)s as a member of collection "%(y)s". Expected an object of type %(z)s or a polymorphic subclass of this type. If %(x)s is a subclass of %(z)s, configure mapper "%(zm)s" to load this subtype polymorphically, or set enable_typechecks=False to allow any subtype to be accepted for flush. )xyzZzmzAttempting to flush an item of type %(x)s as a member of collection "%(y)s". Expected an object of type %(z)s or a polymorphic subclass of this type.)r]r^r_)ruselistrZ FlushErrorrZ_canloadrclass_r-r$r$r%_verify_canload s8 z#DependencyProcessor._verify_canloadcCs tdSr'NotImplementedError)r#r.rJassociationrow clearkeysrQr$r$r% _synchronize3sz DependencyProcessor._synchronizecCs>|jjs dStt|jgdd|jjD}|d|ftS)NcSsg|] }|jqSr$)r).0pr$r$r% ;szCDependencyProcessor._get_reversed_processed_set..Z reverse_key)r_reverse_propertytuplesortedrmemoset)r#r1Z process_keyr$r$r%_get_reversed_processed_set6s z/DependencyProcessor._get_reversed_processed_setFcCs8|D].}|r|dk r||dd|jjDq4qdS)NcSsg|] \}}|qSr$r$)rhlrr$r$r%rjCsz4DependencyProcessor._post_update..)Zregister_post_updaterr )r#r.rQrelated is_m2o_deleter]r$r$r% _post_update?s z DependencyProcessor._post_updatecCs tdSr'rcr#rQr.r$r$r% _pks_changedGsz DependencyProcessor._pks_changedcCsd|jj|jfS)Nz%s(%s)) __class____name__r)r#r$r$r%__repr__JszDependencyProcessor.__repr__N)F)ry __module__ __qualname__r& classmethodr*r,r2r?rNrRrSrTrUr\rbrgrprurwrzr$r$r$r%rs$  r ) rc@sLeZdZddZddZddZddZd d Zd d Zd dZ ddZ dS) OneToManyDPc Cs|jr\t||jjd}t||jjd} |j||f||f||f|| f| |f| |fgn6|j||f||f||f||f||f||f||fgdSr3rr PostUpdateAllrr6 dependenciesupdate) r#r1r;r<r=r>r9r:child_post_updateschild_pre_updatesr$r$r%r8Os<  z%OneToManyDP.per_property_dependenciesc Cs|jrt||jjd} t||jjd} |sl|rL|j||f|| fgq|j||f||f|| fgq|r|j|| f| |fgq|j|| f| |fgn<|s|j||f||f||fgn|j||f||fgdSr3r) r#r1 save_parent delete_parentrKr9r:rIrMrrr$r$r%rHxsZ z"OneToManyDP.per_state_dependenciescCs|jj o|jdk }|D]}|||j|j}|r|jD]<}|dk r:||dkr:|jjrl|j |ddq:| |q:|r|j D]}|dk r|j |d|j dqqdS)NallFTrIdelete operationr) rrrrWrrrLr, delete_orphanregister_object unchangedrr#rQrFshould_null_fksr.r[rJr$r$r%rRs,   zOneToManyDP.presort_deletesc Csd|d|ft}|jj o$|jdk }|D]2}|||}|rF|jrTtjtj B}n tj tj B}| ||j |}|r&|j D] } | dk r||j| dd|jdq|||j |jD]t} |jjs|r|j| dd|jdq|| dkr|j| dd|jd|jd| D]\} } } } |j| dd qq|r*|r*|jD](} | dk r4|j| d|jd |jd q4q*dS) Nchildren_addedrTadd)Z cancel_deleterrFrrIrrrz pk changer)rnrorrrrwrrrrVrrWraddedrrrrLr,rcascade_iteratorr)r#rQrFrrr. pks_changedrYr[rJcmst_dct_r$r$r%rSst          zOneToManyDP.presort_savesc Cs|js|jdks|d|ft}|D]}|||j|j}|r$|jD]H}|dk rD||dkrD| ||dd|d|jrD|rD| |||gqD|js|j j s$t|j |D]:}|dk r| ||dd|d|jr|r| |||gqq$dS)NrrFT)rrrnrorWrrrLr,rgrurrr difference)r#rQrFrr.r[rJr$r$r%rTsV     zOneToManyDP.process_deletesc Cs|jj o|jdk }|D]}|||jtj}|r|jD]6}|||dd|d|dk r:|j r:| |||gq:|j D].}|rx|jjsx| |sx|||dd|dqx| ||r|jD]}|||dd|dqqdS)NrFT)rrrrWrrrrrgrrurLr,rwrrr$r$r%rUDs\      zOneToManyDP.process_savesc Csp|}|}|||dks*|js.||r.dS|rHt||j|jjn$t||j ||j|jj||j oh|dSr') rbr is_deletedrclearrrr populaterr) r#r.rJrerfrQrsourcedestr$r$r%rgfs( zOneToManyDP._synchronizecCst|||j|jjSr'rsource_modifiedrrr rvr$r$r%rw}s zOneToManyDP._pks_changedN) ryr{r|r8rHrRrSrTrUrgrwr$r$r$r%r~Ns)AD,"r~c@sNeZdZddZddZddZddZd d Zd d Zd dZ dddZ dS) ManyToOneDPcCs.t|||jjD]}|jt|qdSr')rr&rZself_and_descendantsZ_dependency_processorsrGDetectKeySwitch)r#rrr$r$r%r&s  zManyToOneDP.__init__c Cs|jrbt||jjd}t||jjd} |j||f||f||f|| f|| f| |f| |fgn$|j||f||f||f||fgdSr3rrrrr6rr) r#r1r;r<r=r>r9r:parent_post_updatesparent_pre_updatesr$r$r%r8s8  z%ManyToOneDP.per_property_dependenciesc Cs|jr|sZt||jjd} |r:|j|| f| |fgq|j||f||f|| fgqt||jjd} |j|| f| |f| |fgnL|s|s|j||f||fgq|j||fgn|r|j||fgdSr3r) r#r1rrrKr9r:rIrMrrr$r$r%rHsL z"ManyToOneDP.per_state_dependenciesc Cs|jjs|jjr|D]}|||j|j}|r|jjr@|}n|}|D]P}|dkrZqL|j|dd|j d|j d|}|D]\}} } } |j| ddqqLqdS)NTrrr) rrrrWrrsumZ non_deletedrrrr) r#rQrFr.r[ZtodeleterJtrrrrr$r$r%rRs. zManyToOneDP.presort_deletesc Cs|D]}|j|d|jd|jjr|||j|j}|r|jD]T}||dkr>|j|dd|jd|j d|}|D]\}}} } |j| ddqvq>qdS)NrrFTrrr) rrrrrWrrrLr,rr) r#rQrFr.r[rJrrrrrr$r$r%rSs( zManyToOneDP.presort_savescCsn|jrj|jjsj|jdksj|D]L}||ddd||r|jr|||j|j}|r|j||| ddqdS)NrT)rt) rrrrrgrWrrrur)r#rQrFr.r[r$r$r%rTs* zManyToOneDP.process_deletesc Cs~|D]t}|||jtj}|r|jrF|jD]}|||dd|dq*n|jr`||ddd|d|jr|||| qdS)NFrTr) rWrrrrrgrLrrur)r#rQrFr.r[rJr$r$r%rU)s8 zManyToOneDP.process_savesNc Cs|dks|js||rdS|dk rX|dk rX|j|sXtdt|||jfdS|sd|dkrzt ||j |jj n(| |t ||j||j |jj |ddS)NGObject of type %s not in session, %s operation along '%s' won't proceedF)rrsession_contains_staterwarn mapperutilstate_class_strrrrrr rbrrr#r.rJrerfrQrr$r$r%rg;s<    zManyToOneDP._synchronize)N) ryr{r|r&r8rHrRrSrTrUrgr$r$r$r%rs'8rc@sheZdZdZddZddZddZdd Zd d Zd d Z ddZ ddZ ddZ ddZ ddZdS)raFor many-to-one relationships with no one-to-many backref, searches for parents through the unit of work when a primary key has changed and updates them. Theoretically, this approach could be expanded to support transparent deletion of objects referenced via many-to-one as well, although the current attribute system doesn't do enough bookkeeping for this to be efficient. cCs<|jjr,|jrdSddd|jjDkr,dS||ddS)NFcss|] }|jVqdSr')r)rhrr$r$r% usz=DetectKeySwitch.per_property_preprocessors..)rrkrr/r0r$r$r%r2psz*DetectKeySwitch.per_property_preprocessorscCs6t||jj}t||dd}|j||fgdSrO)rr5rrBr4rr)r#r1r;r9r$r$r%r?}sz*DetectKeySwitch.per_property_flush_actionscCsdSr'r$)r#r1rFrIr$r$r%rNsz'DetectKeySwitch.per_state_flush_actionscCsdSr'r$rPr$r$r%rRszDetectKeySwitch.presort_deletescCs|js|||dSr')r_process_key_switches)r#r1rFr$r$r%rSszDetectKeySwitch.presort_savescCs"|s|jr|||}t|SdSrO)r_key_switchersbool)r#r1rFrIdr$r$r%r\s  z DetectKeySwitch.prop_has_changescCs dstdSrO)rArPr$r$r%rTszDetectKeySwitch.process_deletescCs|js t|||dSr')rrArrPr$r$r%rUs zDetectKeySwitch.process_savescCsZ|d|fdd\}}||}|D].}||kr&|||rJ||q&||q&|S)NZ pk_switcherscSs ttfSr')ror$r$r$r%z0DetectKeySwitch._key_switchers..)rnunionrwr)r#r1rFZswitchedZ notswitchedZ allstatesrZr$r$r%rs    zDetectKeySwitch._key_switchersc Cs|||}|r|jjD]}t|j|jjs2q|j}||j j |||j d}|t j k r|dk r|jjr||srq|d}n|}t |}||kr||d|jt||j||j|jj||jqdS)N)rYrF)rrZ identity_mapZ all_states issubclassrarrEr+rgetrrZPASSIVE_NO_RESULTrr`Zinstance_staterrrrrr ) r#ZdeplistrQZ switchersr.Zdict_rsZ related_objZ related_stater$r$r%rsH    z%DetectKeySwitch._process_key_switchescCs t|jot|||j|jjSr')rrrrrrr rvr$r$r%rws zDetectKeySwitch._pks_changedN)ryr{r|__doc__r2r?rNrRrSr\rTrUrrrwr$r$r$r%rds  %rc@sTeZdZddZddZddZddZd d Zd d Zd dZ ddZ ddZ dS) ManyToManyDPc Cs:|j||f||f||f||f||f||f||fgdSr'rr)r#r1r;r<r=r>r9r:r$r$r%r8s z&ManyToManyDP.per_property_dependenciesc CsX|s<|r"|j||f||fgqT|j||f||fgn|j||f||fgdSr'r) r#r1rrrKr9r:rIrMr$r$r%rHs z#ManyToManyDP.per_state_dependenciescCs&|js"|D]}|||j|jq dSr')rrWrr)r#rQrFr.r$r$r%rRszManyToManyDP.presort_deletesc Cs|js.|D]"}|||r |||jtj}q |jjs:dS|D]r}|||jtj}|r>|j D]P}| |dkr^|j |dd|j d|j d|D]\}}}} |j |ddqq^q>dS)NFTrrr)rrwrWrrrrrrrLr,rrrr) r#rQrFr.r[rJrrrrr$r$r%rSs<  zManyToManyDP.presort_savesc sg}g}g}||}t}|D]||j|j}|r |D]F} | dksB|dk rd| f|krdqBi} || | d|ds~qB|| qB|fdd|Dq |dk r||| ||||dS)NFrc3s|]}|fVqdSr'r$rhrr.r$r%r[sz/ManyToManyDP.process_deletes..) rprorWrrZ non_addedrgrGr _run_crud) r#rQrFsecondary_deletesecondary_insertsecondary_update processedtmpr[rJrer$rr%rT<sN     zManyToManyDP.process_deletesc sg}g}g}||}t}|D]F|j o8||}|rLtjtjB} n tjtjB} ||j | } | r | j D]>} |dk r| f|krqri} | | | d|dsqr| | qr| j D]>} |dk r҈| f|krqi} | | | d|dsq| | q|fdd| j | j D|r | jD]D} i} t|j| d|jjt| |j| d|jj| | q"q |dk r~|||||||dS)NFrrc3s|]}|fVqdSr'r$rrr$r%rsz-ManyToManyDP.process_saves..old_)rprorrwrrrVrrWrrrgrGrLrrrrrr rsecondary_synchronize_pairsr) r#rQrFrrrrrZneed_cascade_pksrYr[rJrer$rr%rUds           zManyToManyDP.process_savescs|j|j}|r|d|jtjfdd|jjD}| ||}| r|j t |krt d|jjt ||j f|r|d|jtjfdd|jjD}| ||}| r|j t |krt d|jjt ||j f|r|j}| ||dS)Nrcs,g|]$}|jkr|tj|j|jdkqS)type_rr Z bindparamtyperrer$r%rjs z*ManyToManyDP._run_crud..zRDELETE statement on table '%s' expected to delete %d row(s); Only %d were matched.cs0g|](}|jkr|tjd|j|jdkqS)rrrrrr$r%rjs zRUPDATE statement on table '%s' expected to update %d row(s); Only %d were matched.)Z transaction connectionrrrwherer and_rexecuteZsupports_sane_multi_rowcountZrowcountlenrZStaleDataError descriptionrinsert)r#rQrrrrZ statementresultr$rr%rs`           zManyToManyDP._run_crudcCs|||dkrdS|dk rP|j|sP|jsLtdt|||jfdSt ||j ||jj t ||j ||jjdS)NFrT)rbrrrLrrrrrrZ populate_dictrr rrrr$r$r%rgs0 zManyToManyDP._synchronizecCst|||j|jjSr'rrvr$r$r%rws zManyToManyDP._pks_changedN) ryr{r|r8rHrRrSrTrUrrgrwr$r$r$r%rs "(M= rN)r __future__rrrrrrrZ interfacesr r r r!r rr~rrrr(r$r$r$r% s>            37bu>