
    AhBb                         d Z ddlZddlmZ ddlmZ ddlmZmZ ddl	m
Z
 ddlmZ ddlmZmZ dd	lmZ d
 Zd Z G d dej*                  j,                        Z G d dej0                        Z G d de      Zy)zNested Sets    N)reduce)serializers)
connectionmodels)Q)gettext_noop)InvalidMoveToDescendantNodeAlreadySaved)Nodec                     | j                   j                  d      j                  }| j                   j                  |k(  r| S |S )a  
    For the given model class, determine what class we should use for the
    nodes returned by its tree methods (such as get_children).

    Usually this will be trivially the same as the initial model class,
    but there are special cases when model inheritance is in use:

    * If the model extends another via multi-table inheritance, we need to
      use whichever ancestor originally implemented the tree behaviour (i.e.
      the one which defines the 'lft'/'rgt' fields). We can't use the
      subclass, because it's not guaranteed that the other nodes reachable
      from the current one will be instances of the same subclass.

    * If the model is a proxy model, the returned nodes should also use
      the proxy class.
    lft)_meta	get_fieldmodelproxy_for_model)cls
base_classs     A/home/dcms/DCMS/lib/python3.12/site-packages/treebeard/ns_tree.pyget_result_classr      s;    " $$U+11J
yy  J.
    c           	          t        | d         t        |d         z  D ci c].  }|| d   j                  |d      |d   j                  |d      z   0 }}| d   |d   z   |fS c c}w )zE
    Merge return values from Django's Queryset.delete() method.
       r   )setget)c1c2keyobject_countss       r   merge_deleted_countersr   '   s|     r!u:BqE
* 	RUYYsAA3!222M  qEBqEM=))	s   3A"c                   F     e Zd ZdZddd fd
Zde_        de_         xZS )NS_NodeQuerySetzg
    Custom queryset for the tree node manager.

    Needed only for the customized delete method.
    Nremoved_rangesdeleted_counterc                   t        | j                        }|di f}|lt        |   |i |}t	        ||      }|j                  d      }t        |d      D ].  \  }}	}
|j                  |	|
|      \  }}|j                  ||       0 |S i }| j                  dd      D ]C  }d}|j                         D ]  \  }}|j                  |      sd} n |r5|||j                  <   E g }g }|j                         D ]  \  }}|j                  t        |j                  |j                   f      t        |j"                  	      z         |j                  |j"                  |j                  |j                   f        |rD|j$                  j'                  t)        t*        j,                  |            j                  ||
      }|S )a  
        Custom delete method, will remove all descendant nodes to ensure a
        consistent tree (no orphans)

        :returns: tuple of the number of objects deleted and a dictionary 
                  with the number of deletions per object type
        r   writeT)reversetree_idr   F)
lft__range)r(   r"   )r   r   superdeleter   _get_database_cursorsorted_get_close_gap_sqlexecuteorder_byitemsis_descendant_ofpkappendr   r   rgtr(   objectsfilterr   operatoror_)selfr#   r$   argskwargsr   resultcursorr(   drop_lftdrop_rgtsqlparamsremovednodefoundridrnodetoremoverangesid	__class__s                        r   r+   zNS_NodeQuerySet.delete9   s    !," "gO% W^T4V4F4_fMO//8F 06n>B0D ,+8#66x<CEVsF+	,@ / Gi7 ,")--/ JC,,U3 $ '+GDGG$, HF#MMO BDdhh-A B !$,, 7!8 9t||TXXtxx@AB "'--"6"68<<#%# &&P   r   T)__name__
__module____qualname____doc__r+   alters_dataqueryset_only__classcell__)rK   s   @r   r!   r!   2   s*     ,0 ;z FFr   r!   c                       e Zd ZdZd Zy)NS_NodeManagerz/Custom manager for nodes in a Nested Sets tree.c                 L    t        | j                        j                  dd      S )z(Sets the custom queryset as the default.r(   r   )r!   r   r0   r:   s    r   get_querysetzNS_NodeManager.get_queryset}   s    tzz*33IuEEr   N)rL   rM   rN   rO   rW    r   r   rT   rT   z   s    9Fr   rT   c                      e Zd ZdZg Z ej                  d      Z ej                  d      Z ej                  d      Z	 ej                  d      Z
 e       Zed        Zedd       Zed        Zd Zdd	Zdd
Zed        Zedd       Zd Zd Zd Zd Zd Zd Zed d       Zedd       Zd Zd Zd Z d Z!d!dZ"ed        Z# G d d      Z$y)"NS_Nodez4Abstract model to create your own Nested Sets Trees.T)db_indexc                 x   | j                         }|r|j                  r |j                  di |S |r|j                  dz   }nd}t	        |      dk(  r*d|v r&|d   }|j
                  j                  st        d       t        |       di |}d|_	        ||_        d|_
        d|_        |j                          |S )zAdds a root node to the tree.r   instance<Attempted to add a tree node that is already in the database   )sorted-siblingrX   )get_last_root_nodenode_order_byadd_siblingr(   len_stateaddingr
   r   depthr   r5   save)r   r<   	last_root
newtree_idnewobjs        r   add_rootzNS_Node.add_root   s    
 **,	00 )9((DVDD"**Q.J Jv;!
f 4J'F==''& (. / / +%c*4V4F#

r   c                     |rd}nd}dt         j                  j                  t        |       j                  j
                        ||||dz  }|g fS )Nz>=>a0  UPDATE %(table)s  SET lft = CASE WHEN lft %(lftop)s %(parent_rgt)d                 THEN lft %(incdec)+d                 ELSE lft END,      rgt = CASE WHEN rgt >= %(parent_rgt)d                 THEN rgt %(incdec)+d                 ELSE rgt END  WHERE rgt >= %(parent_rgt)d AND        tree_id = %(tree_id)s)table
parent_rgtr(   lftopincdecr   ops
quote_namer   r   db_table)r   r(   r5   lftmoverr   rq   rA   s          r   _move_rightzNS_Node._move_right   s_    EE- &>>44&s+11::< #$ "0$$ Bwr   c                     dt         j                  j                  t        |       j                  j
                        |dz  }|g fS )NzGUPDATE %(table)s  SET tree_id = tree_id+1  WHERE tree_id >= %(tree_id)d)ro   r(   rs   )r   r(   rA   s      r   _move_tree_rightzNS_Node._move_tree_right   sI    . &>>44&s+11::<$1&& Bwr   c                    | j                         s;| j                  rd}nd}| j                         }| |_         |j                  |fi |S | j
                  j                  | j                  | j                  dd      \  }}t        |      dk(  r*d|v r&|d   }|j                  j                  s&t        d       t        | j
                        d	i |}| j                  |_        | j                  dz   |_        | j                  dz   |_        | j                  dz   |_        | xj                  dz  c_        | |_        | j!                  d      }|j#                  ||       |j%                          |S )
zAdds a child to the node.r`   last-siblingFr_   r   r]   r^   r&   rX   )is_leafrb   get_last_child_cached_parent_objrc   rK   rx   r(   r5   rd   re   rf   r
   r   rg   r   r,   r/   rh   )r:   r<   pos
last_childrA   rB   rk   r>   s           r   	add_childzNS_Node.add_child   sN   ||~!!&$,,.J,0J)):))#888 nn00155!EV v;!
f 4J'F==''& (. / / 6%dnn5??FzzA~XX\
XX\
 	A$(!**73sF# 	r   Nc                    | j                  |      }t        |      dk(  r*d|v r&|d   }|j                  j                  s&t	        d       t        | j                        di |}| j                  |_        d}| }|j                         rd|_	        d|_
        |dk(  r5t        |j                  |j                         |            }|rd}|d   }nd	}|j                  j                         }|d	k(  s
|d
k(  r||k(  r|j                  dz   |_        nd|j                  |j                  dz   d|   }|j                  j!                  |      \  }}	||_        n_|j                  |_        |dk(  r5t        |j                  |j                         |            }|rd}|d   }nd	}|dv r[t        |j                               }|d
k(  r$||d   k(  rd	}nd}d}
|D ]  }|
r|} n
||k(  sd}
 |dk(  r
||d   k(  rd}|dk(  r|d   }| j                  j"                  }|d	k(  r3|j%                         j                  } ||j                  |dd      \  }}	nV|dk(  r(|j                  } ||j                  |dz
  dd      \  }}	n)|dk(  r$|j                  } ||j                  |dd      \  }}	|_	        |dz   |_
        |r#| j'                  d      }|j)                  |	       |j+                          |S )z8Adds a new node as a sibling to the current node object.r   r]   r^   Nr_   r`   leftr   r|   right)first-siblingr   r   r   r   r   FTr   r&   rX   ) _prepare_pos_var_for_add_siblingrd   re   rf   r
   r   rK   rg   is_rootr   r5   listget_sorted_pos_querysetget_siblingsra   r(   rz   rx   
get_parentr,   r/   rh   )r:   r   r<   rk   rA   targetsiblingsri   newposrB   rE   rD   
move_rightr>   s                 r   rc   zNS_Node.add_sibling   s    33C8v;!
f 4J'F==''& (. / / 6%dnn5??Fzz>>FJFJ&& > >'')6!3 4 C%a[F(C((;;=IN*G^)(;!*!2!2Q!6+,"(..#)>>A#577:< %..??GV!'#^^FN&& > >'')6!3 4 C%a[F(C88 3 3 56'>"-,$ %$, -D$)- %!%(,- &=!,-/)%a[F33Jn$**,00(JV'(!UANV(qIVFJ!FJ ..w7FNN3'r   c           	         | j                  |      }t        | j                        }d}|dv r.|j                         r|}d}n|j	                         }dddd|   }|j                  |       rt        t        d            | |k(  r5|dk(  s/|d	v r||j                         k(  s|dk(  r||j                         k(  ry|dk(  r5t        |j                  |j                         |             }|rd}|d
   }nd}|dv r[t        |j                               }|dk(  r$||d   k(  rd}nd}d}|D ]  }|r|} n
||k(  sd} |dk(  r
||d
   k(  rd}|dk(  r|d
   }| j                  d      }|j                  }	| j                  | j                   z
  dz   }
d}|j"                  }|dk(  r&|j                  } |	|j"                  |d|
      \  }}n|j%                         rvd}|dk(  r/|j                         j'                         d
   j"                  dz   }n|dk(  rd}|j)                  d      \  }}n|dk(  r|j)                  |j"                        \  }}n|dk(  r3|j+                         j                  } |	|j"                  |d|
      \  }}nV|dk(  r(|j                   } |	|j"                  |dz
  d|
      \  }}n)|dk(  r$|j                   } |	|j"                  |d|
      \  }}|r|j-                  |       |j.                  j1                  | j2                        }|j4                  |j4                  z
  }|r|dz  }dt6        j8                  j;                  |j<                  j>                        |j"                  ||j                   z
  ||j                   |j                  dz  }|j-                  |g        |jA                  |j                   |j                  |j"                        \  }}|j-                  ||       y)zu
        Moves the current node and all it's descendants to a new position
        relative to another node.
        N)zfirst-child
last-childzsorted-childr   r   r|   r`   z Can't move node to a descendant.r   )r   r|   r   r   r   r   FTr&   r   r3   zUPDATE %(table)s  SET tree_id = %(target_tree)d,      lft = lft + %(jump)d ,      rgt = rgt + %(jump)d ,      depth = depth + %(depthdiff)d  WHERE tree_id = %(from_tree)d AND      lft BETWEEN %(fromlft)d AND %(fromrgt)d)ro   	from_treetarget_treejump	depthdifffromlftfromrgt)!_prepare_pos_var_for_mover   rK   r}   r~   r2   r	   _get_last_siblingget_first_siblingr   r   r   r,   rx   r5   r   r(   r   r'   rz   r   r/   r6   r   r3   rg   r   rt   ru   r   rv   r.   )r:   r   r   r   parentr   rE   rD   r>   r   gaprA   r   r   rB   fromobjr   s                    r   movezNS_Node.moved  s    ,,S1t~~.??~~"..0&5%3'799<> ""4()457 7 6>F]--v..00O#v//11""F::##%t- .H!!$44F//12Hg~Xb\)(C C!E ( ) %)F!!V^$(E) f}Xa[()Co%!! **73__
hh!A%nn ,ZZF$V^^VUCHKC^^Fn$$113;;=a@HH1L'!2215V!226>>BVn$**,00(LV'()/!UCAV(sKVNN3' ++//TWW/-LL7==0	NI= &>>44SYY5G5GH&!, 7;;.($[[$[[@** 	sB ,,W[[-4[['//KVsF#r   c                     dt         j                  j                  t        |       j                  j
                        ||z
  dz   ||dz  }|g fS )Na?  UPDATE %(table)s  SET lft = CASE            WHEN lft > %(drop_lft)d            THEN lft - %(gapsize)d            ELSE lft END,      rgt = CASE            WHEN rgt > %(drop_lft)d            THEN rgt - %(gapsize)d            ELSE rgt END  WHERE (lft > %(drop_lft)d      OR rgt > %(drop_lft)d) AND      tree_id=%(tree_id)dr   )ro   gapsizer?   r(   rs   )r   r?   r@   r(   rA   s        r   r.   zNS_Node._get_close_gap_sql  sY    ) &>>44&s+11::<%014&$,&&" Bwr   c                    t        |       } g }|r|j                  }nd}|ddd   D cg c]  }||f }}| j                         }| j                  j                  j                  }	|r|j                         \  }}
|
d   j                         }| j                  ||       |r|
|	   ||	<   |r/| j                  j                  |      } |j                  di |}n | j                  di |}|j                  |j                         d|
v r4|j                  |
d   ddd   D cg c]  }|j                  |f c}       |r|S c c}w c c}w )z.Loads a list/dictionary structure to the tree.Nr   datar   childrenrX   )r   r3   get_foreign_keysr   attnamepopcopy_process_foreign_keysr6   r   r   rl   r4   extend)r   	bulk_datar   keep_idsadded	parent_idrD   stackforeign_keyspk_fieldnode_struct	node_datanode_objs                r   	load_bulkzNS_Node.load_bulk  sX    s# 		II/82?t)T"??++-99<<''%*YY["I{#F+002I%%lI>&1(&;	(#I6+6++8i8'3<<4)4LL%[(  +J 7" = [[$' ! ( / @&s   E$E
c                 \    | j                         j                  | j                  dz         S )z/:returns: A queryset of all the node's childrenr   rg   )get_descendantsr7   rg   rV   s    r   get_childrenzNS_Node.get_children   s'    ##%,,4::>,BBr   c                     | j                   S )z':returns: the depth (level) of the noder   rV   s    r   	get_depthzNS_Node.get_depth$  s    zzr   c                 :    | j                   | j                  z
  dk(  S )z?:returns: True if the node is a leaf node (else, returns False)r   r5   r   rV   s    r   r}   zNS_Node.is_leaf(  s    xx$(("a''r   c                     | j                   dk(  r| S t        | j                        j                  j	                  | j
                  d      S )z4:returns: the root node for the current node object.r   )r(   r   )r   r   rK   r6   r   r(   rV   s    r   get_rootzNS_Node.get_root,  sB    88q=K/77;;LLa < ) 	)r   c                      | j                   dk(  S )z?:returns: True if the node is a root node (else, returns False)r   r   rV   s    r   r   zNS_Node.is_root3  s    xx1}r   c                 ~    | j                   dk(  r| j                         S | j                  d      j                         S )zi
        :returns: A queryset of all the node's siblings, including the node
            itself.
        r   T)r   get_root_nodesr   r   rV   s    r   r   zNS_Node.get_siblings7  s6    
 88q=&&((t$1133r   c                    | j                         j                  |      }g i }}| j                  j                  j                  }|D ]  }t        j                  d|g      d   }|d   }	|	d   }
|	d= |	d= |	d= |	d= ||	v r|	|= d|	i}|r|d	   ||<   |s|
d
k(  s|r!|
|j                  k(  r|j                  |       n<|j                         }||j                     }d|vrg |d<   |d   j                  |       |||j                  <    |S )z/Dumps a tree branch to a python data structure.pythonr   fieldsrg   r   r5   r(   r   r3   r   r   )
_get_serializable_modelget_treer   r3   r   r   	serializerg   r4   r   )r   r   r   qsetretlnkr   pyobjserobjr   rg   rk   	parentobj	parentsers                 r   	dump_bulkzNS_Node.dump_bulk@  s4    **,55f=rS99<<'' 	#E **8eW=a@FH%F7OEuuwy!6!8$f%F#)$<x uz5FLL0

6"!,,.		-	Y.,.Ij)*%,,V4"CM7	#8 
r   c                 <   t        |       } || j                  j                         S |j                         r&| j                  j	                  |j
                        S | j                  j	                  |j                  |j                  |j                  dz
  f      S )z
        :returns:

            A *queryset* of nodes ordered as DFS, including the parent.
            If no parent is given, all trees are returned.
        r   r   )r(   r)   )	r   r6   allr}   r7   r3   r(   r   r5   )r   r   s     r   r   zNS_Node.get_treed  s     s#>;;??$$>>;;%%%33{{!!NN

FJJN3 " 5 	5r   c                     | j                         r-t        | j                        j                  j	                         S | j                  j                  |       j                  | j                        S )zx
        :returns: A queryset of all the node's descendants as DFS, doesn't
            include the node itself
        r   )r}   r   rK   r6   noner   excluder3   rV   s    r   r   zNS_Node.get_descendantsw  sR    
 <<>#DNN3;;@@BB~~&&t,444@@r   c                 @    | j                   | j                  z
  dz
  dz  S )z.:returns: the number of descendants of a node.r   r_   r   rV   s    r   get_descendant_countzNS_Node.get_descendant_count  s    488#a'1,,r   c                    | j                         r-t        | j                        j                  j	                         S t        | j                        j                  j                  | j                  | j                  | j                        S )z
        :returns: A queryset containing the current node object's ancestors,
            starting by the root node and descending to the parent.
        )r(   lft__ltrgt__gt)	r   r   rK   r6   r   r7   r(   r   r5   rV   s    r   get_ancestorszNS_Node.get_ancestors  sg    
 <<>#DNN3;;@@BB/77>>LLHHHH ?  	r   c                     | j                   |j                   k(  xr4 | j                  |j                  kD  xr | j                  |j                  k  S )z
        :returns: ``True`` if the node if a descendant of another node given
            as an argument, else, returns ``False``
        )r(   r   r5   )r:   rD   s     r   r2   zNS_Node.is_descendant_of  sC     LLDLL(  HHtxx HHtxx	
r   c                     | j                         ry	 |r| `n| j                  S 	 | j                         j	                         d   | _        | j                  S # t        $ r Y =w xY w)z
        :returns: the parent node of the current node object.
            Caches the result in the object itself to help in loops.
        Nr   )r   r   AttributeErrorr   r'   )r:   updates     r   r   zNS_Node.get_parent  sp    
 <<>	+... , #'"4"4"6">">"@"C&&&	  		s   A 	A#"A#c                 L    t        |       j                  j                  d      S )z;:returns: A queryset containing the root nodes in the tree.r   r   )r   r6   r7   )r   s    r   r   zNS_Node.get_root_nodes  s#      $,,333::r   c                       e Zd ZdZdZy)NS_Node.MetazAbstract model.TN)rL   rM   rN   rO   abstractrX   r   r   Metar     s
    r   r   )Fr_   )N)NF)NT)F)%rL   rM   rN   rO   rb   r   PositiveIntegerFieldr   r5   r(   rg   rT   r6   classmethodrl   rx   rz   r   rc   r   r.   r   r   r   r}   r   r   r   r   r   r   r   r   r2   r   r   r   rX   r   r   rZ   rZ      sR   >M
%&
%
%t
4C
%&
%
%t
4C)f))48G'F''6EG" "H  ,  *XcJ$B  ( # #JC()4 ! !F 5 5$A-
	
'$ ; ; r   rZ   )rO   r8   	functoolsr   django.corer   	django.dbr   r   django.db.modelsr   django.utils.translationr   r   treebeard.exceptionsr	   r
   treebeard.modelsr   r   r   queryQuerySetr!   ManagerrT   rZ   rX   r   r   <module>r      sc       # (  6 J !0*E fll++ E PFV^^ Frd rr   