From 313919503e7e62bc39d3a6742a899261b837e1f6 Mon Sep 17 00:00:00 2001 From: icter99 <1622324630@qq.com> Date: Tue, 24 Dec 2024 20:14:19 +0800 Subject: [PATCH] push the test --- app/__pycache__/__init__.cpython-312.pyc | Bin 145 -> 145 bytes app/__pycache__/__init__.cpython-38.pyc | Bin 130 -> 127 bytes app/__pycache__/config.cpython-312.pyc | Bin 781 -> 781 bytes app/__pycache__/config.cpython-38.pyc | Bin 679 -> 676 bytes app/__pycache__/database.cpython-312.pyc | Bin 1257 -> 1372 bytes app/__pycache__/database.cpython-38.pyc | Bin 946 -> 1061 bytes app/__pycache__/locustfile.cpython-38.pyc | Bin 0 -> 1143 bytes app/__pycache__/main.cpython-312.pyc | Bin 990 -> 990 bytes app/__pycache__/main.cpython-38.pyc | Bin 723 -> 720 bytes app/database.py | 11 +-- app/locustfile.py | 24 ++++++ .../__pycache__/__init__.cpython-312.pyc | Bin 153 -> 153 bytes .../__pycache__/__init__.cpython-38.pyc | Bin 138 -> 983 bytes app/routers/__pycache__/user.cpython-312.pyc | Bin 3710 -> 3361 bytes app/routers/__pycache__/user.cpython-38.pyc | Bin 2823 -> 2525 bytes app/routers/user.py | 52 ++++++++----- .../__pycache__/__init__.cpython-312.pyc | Bin 153 -> 153 bytes .../__pycache__/__init__.cpython-38.pyc | Bin 138 -> 135 bytes app/schemas/__pycache__/user.cpython-312.pyc | Bin 919 -> 919 bytes app/schemas/__pycache__/user.cpython-38.pyc | Bin 799 -> 796 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 154 -> 154 bytes .../__pycache__/__init__.cpython-38.pyc | Bin 139 -> 136 bytes .../__pycache__/user_service.cpython-312.pyc | Bin 8897 -> 9118 bytes .../__pycache__/user_service.cpython-38.pyc | Bin 6309 -> 5755 bytes app/services/user_service.py | 71 ++++++------------ app/test/__init__.py | 0 app/test/__pycache__/__init__.cpython-38.pyc | Bin 0 -> 132 bytes .../test.cpython-38-pytest-8.3.3.pyc | Bin 0 -> 7017 bytes app/test/test.py | 61 +++++++++++++++ 29 files changed, 146 insertions(+), 73 deletions(-) create mode 100644 app/__pycache__/locustfile.cpython-38.pyc create mode 100644 app/locustfile.py create mode 100644 app/test/__init__.py create mode 100644 app/test/__pycache__/__init__.cpython-38.pyc create mode 100644 app/test/__pycache__/test.cpython-38-pytest-8.3.3.pyc create mode 100644 app/test/test.py diff --git a/app/__pycache__/__init__.cpython-312.pyc b/app/__pycache__/__init__.cpython-312.pyc index 4bfaeb835190596c5e415dbc07b0a9afd397ae9d..48ffa41771b30f3c77fda693de8fdca1caf6d722 100644 GIT binary patch delta 19 ZcmbQpIFXV2G%qg~0}xn5x=!S70{|#{1Q!4R delta 19 ZcmbQpIFXV2G%qg~0}vR#N}I^t1^_Fn1i}CS diff --git a/app/__pycache__/__init__.cpython-38.pyc b/app/__pycache__/__init__.cpython-38.pyc index 767f2bdd1ac08cd10647fb0e30614df9b3fdb45b..5b06b223a44cc65331a015e69cd7619107558b82 100644 GIT binary patch delta 30 lcmZo-te@a6s^Vf5Q&3rwk)IcnoS%{!lbvp8WIQom833SV3S9sI delta 33 ocmb<#Vw~VEq3&W8Q&3rwk)IcnoS%{!6YL$IR+OJtGBHLO0LH`&9smFU diff --git a/app/__pycache__/config.cpython-312.pyc b/app/__pycache__/config.cpython-312.pyc index 559bda8623b604ca79e1acb83d85cce1dda841fa..b8a8282571c28ab7588a215c9ca9c82879a2aa77 100644 GIT binary patch delta 20 acmeBW>t*9U&CAQh00hoY;x=+KF#`ZFH3Vk> delta 20 acmeBW>t*9U&CAQh00f4w(l&B4F#`ZF0|a9L diff --git a/app/__pycache__/config.cpython-38.pyc b/app/__pycache__/config.cpython-38.pyc index 3f298f85690a1bb48c04d28e3ab3018fe4b31e5b..aaf2367e7b040692816aacbada5510017e84e7af 100644 GIT binary patch delta 33 pcmZ3^x`cJZN=8v77ps_p%94!yyqM(tl+>8)bVDQK$p;yq0RYGb3|RmG delta 36 scmZ3&x}0^xN=6A)7ps_p%94!yyqM(tl+>7D@A$N${JfIM`xu`A0P-OY8UO$Q diff --git a/app/__pycache__/database.cpython-312.pyc b/app/__pycache__/database.cpython-312.pyc index b96f825acfefddbd8a94d006417ef5b3b7b1aba4..d11a1a98699824e84d65d4a6f30198bb83b624bd 100644 GIT binary patch delta 722 zcmYk3O=uHA6vyXllQeN-Ozm2WwoOYyLa7C<7PJTzp=co>2tqDl&8|(-BpYT@H1%My zp(<1)ESRf;9zqm6sTaY!m&6KzMbLu8G@ArE)L<7~0<70hgSIpg!u^4gGd9D}J7xj{UT^FVkoD=0js`_RHU$9T&373Ii zkOsANJTOV)9iw-K>C2_GGnm(JB~wORxT+rD`t#vW>@gNOD>R$VZbW- zrbXM@R7;zBMc+=pA8ekz+%(glw9I|>(ANb8N@2;pL1A5k*}V!_K-m66PS34DLvF*) zV^X8*ih?jIqZzcJyregA9mk=n?1ZDFa+Wabn5*CknRS#O0&>l6kfAfO@!}ZZJNmtf zzWRfYmL4p%{Ua^^$fiHk_JlrqLOVicx;q@jPjG}ibw#ngMXrPfAo#C}TbM$?tN9U` zZ?B4djZTir#tSKh?195IU)9$RjJE>gn}KlC6XyN)Gdgi62>V=<7y{H0@0a%OHQmyZ zP+$rvte|Z|lq}x%5M`_ji1g%A6r)@gAFBVV0SKY`g za+#KJx4pn-&dI;|UwX$go41VRoOzyyVM9Jj%mRK;jPVzAY7340Vm=)Ci2(LH7G?6* Fe*u2(o2UQ) delta 674 zcmZuuL2DC16n<}Zw%ugA+0xobsA7#Rx-AyPMg)t9q7@JM0l7%YZfZ-i8)n->TA@V> z+C!;f5B&=UJ$Uru!Gk9cHmC%Gf(I}4q|HI_TqM!f=FO3%(gc zd*+VWF>-Aq_t_X%!$kkzz*UOuLlkI*vs{}P7!18IBx!Ym$izVOPP;f^F)>C!$JnEL z8#@~vJKwhRAMMElV^R%ABXVZbrg-dCoupL@Vgvmf3~-1+(unZfy(qbZXM_!Si&U35}i-RJu&ZeTaPSg+5P1HZDoq*yVQj^4_->-;Fk=l(I~Yk|8~ j^=_y<1-PZ*Ji$*55x>G2`hQCkr+xuJbVC`bH9phZ>!b`iK82c zNn+-@$3|A;BU#Ij(rUN&*3OFL&RtAhTb|3b7G;smK#Q!d>$Diz1Y@ip=weav6A(1v zR1wY;RqT>*PkG9RKUAke_y>zR+|EFkFD8d&QRt*j%OdgDBBG3AI0Ui}fz@O}=XB2I z-f0u~%9|4bX`m%Uq~f>#$L zS!wk(HHe|6#s%9!br0A!(5i&}%@P{t|K@KdjWJjGPl&k(>MC!`YHMLl=003*smvBHW*75eV`l$uX55cy+73ZN zvdAJD`H^o>j6H+XFdbxFV1u~Bg9349aOMph_>MixWR{F|KI>2GG&2Z3-i96b0Y#_j z$RHA%fPAZQ762IDUWx!4-do5k@VMn0f^cnAw*|ZC)uP$gxP6Nq?$QqHuwIW*AHTo< E0Kz}>6#xJL literal 946 zcmZ`%&x_MQ6rPz((zM%lMGzLe3X)4toA!ep+N}9x(RM{mr_qrDk zp7q#&X|A697X-ogl15^|3GeaVF3d|M=j%2Cw^R!1LZ$>B2>YGM1!9YgGAI#ZcJQmuH!0x zA6pFu8SAjt0K>J zQl&+n@Loi;QLaGj1*nQ_X-#WZdn*Y1z-l6a1Ol-+WX9utwTYO)JY1km`ca#RJ8pHh za^Bvgj_<8DE-YhfKNUtDh&co7ujkhDe`4fD7{>~l`B)^)iN&2r8<^AD{oyW zWtyjzl-O#EJcQj{oRl!@KnX>_@t}XN$2+jvS{Q+O1eYhg?rg0qc?3*){7+B$ zd$@TNV8`-!r=@fwDR+h1XK0V5{IHL+_K(4MO=0Hozsxus)0Ew9g2fJnG~^*Sco%sl zL=d*bU~ThgDEu6Es#yauf)UP=B44Fz;~@xNiD83~uo7Z)G+{Bsw6(kSaL0e}Jn!}6 ZZ&ogR)mC(g!?oDUF&(q%lu?e~?>|r2&eH$@ diff --git a/app/__pycache__/locustfile.cpython-38.pyc b/app/__pycache__/locustfile.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..53af82e25f0b8cee6f03c685977bd86743d472dc GIT binary patch literal 1143 zcmZuvT~E|N6rGQ@Tgn2WV1kK07-P~G79<*DjKOFk`mixEyfm9kN@v(D^kbb45;ph* z|H2UA(Z4jWKJ8!d$$MK^7G;u|-szmV_nvcRdu}cuFwTDN^*?b!e&c3(II!7-S*^h$ ziKH2c@XIoqvxwz9;<*z!lzbqPOXrkGN3jzgxsrY%p*x0Kq#JVUZy7V(u9UWpiK~6v z+EM0EsUktZ^l)Lb3A5UQMUjX~5;4UkmF$E?4i=HF^kl2=My~RtFK15435{A12XeNK zeTds~u8wEqJT$UkTW>#q#QI|jdB;GNSh{ZMhNUkoeHpR!=Lw!%4F&_S0-fEsZ_Qb1=omQMBjxj{ycsEsy93`gRg)!~s{hCJfx`lO3lWP_Fx-ln66my)dBioGERN`so!a@>IcBmhAq zols}p(b6^bNySdc^a9{DUJ9vR#2A@0%RPwfBG!+yOiXSeszM708?8)tc>{H$LqsF9 zy2Hm1pkerGE?8|CJLi(4VP|0BrCm-}dw?9H(W3{qb)TtkD(i%fZUe-&(807YQ;b;6 z$htM~Ut;%>*o2hWITAH&8FDo)FmU0~G{67B-7v7e5Jj9TA#5N-Udn?E%VULeSdYN@Y3!{Xxi&acPWl2VUUQBX+N@`57cYIn=eqPDunT+O)00w^zm;e9( diff --git a/app/database.py b/app/database.py index d1e57d5..52648f5 100644 --- a/app/database.py +++ b/app/database.py @@ -1,18 +1,19 @@ -from neo4j import GraphDatabase +from neo4j import GraphDatabase, AsyncGraphDatabase + from app.config import settings class Neo4jConnection: def __init__(self, uri, user, password): # 初始化连接,只负责连接 - self.driver = GraphDatabase.driver(uri, auth=(user, password)) + self.driver = AsyncGraphDatabase.driver(uri, auth=(user, password), max_connection_pool_size=100) - def close(self): + async def close(self): # 关闭连接 - self.driver.close() + await self.driver.close() def get_session(self): # 提供 session 对象,供外部查询使用 - return self.driver.session() + return self.driver.session() # 初始化全局 Neo4j 连接 neo4j_conn = Neo4jConnection( diff --git a/app/locustfile.py b/app/locustfile.py new file mode 100644 index 0000000..79c4173 --- /dev/null +++ b/app/locustfile.py @@ -0,0 +1,24 @@ +import random +from locust import HttpUser, task, between + +class APIUser(HttpUser): + # 设置模拟用户之间的等待时间(例如:每个用户之间随机等待 1-3 秒) + wait_time = between(1, 3) + + # 定义一个包含多个章节 ID 的列表 + chapter_ids = ["1", "3", "6", "8", "15"] + + @task + def get_chapter_relations(self): + # 从章节 ID 列表中随机选择一个章节 ID + chapter_id = random.choice(self.chapter_ids) + self.client.get(f"/chapters/{chapter_id}/relations") + + @task + def get_all_relations(self): + self.client.get("/chapters/relations/") + + @task + def get_relations_by_level(self): + level = random.randint(1, 5) # 随机选择一个层级,范围为 1 到 5 + self.client.get(f"/chapters/relations/level/{level}") diff --git a/app/routers/__pycache__/__init__.cpython-312.pyc b/app/routers/__pycache__/__init__.cpython-312.pyc index 000e76868d620dd77b4c82afc1cd2f806f131d49..9f8e648e27fadf893d87c12665cbebc4bf4f5448 100644 GIT binary patch delta 19 ZcmbQqIFph4G%qg~0}vcqk~NXL4*)Le1t|ak delta 19 ZcmbQqIFph4G%qg~0}vR#N}I^t2LLS61lj-q diff --git a/app/routers/__pycache__/__init__.cpython-38.pyc b/app/routers/__pycache__/__init__.cpython-38.pyc index 2a943faf8ac0a3c87e4e7d597c84604683ec1891..cc321bae5746ecf115c21575636aa2f84bea1bb5 100644 GIT binary patch literal 983 zcmZWny=xRf6rY*>xV_Ehat6gHR_PYx@S~Fugrt-dIc=7cW!)L>HrX#{=D?G)GTJ2~ zqFAKJ6&5KX=@hi}pP1HMH25D_`DQnPr~~t6-tgx4-uwODgV|XZ!Sc5^`rimb-?ejo z+2GuTEhrd@C{9sOpE$talaypeU|{`bq-JIX7Dfzh*wmyJyxFv|Z3YeIP-hp@CUv*W zph@SL!whC!LCmGzu0dyMYs(5|DDEP^eFB-#nva!vFA);X%PWJZl#H*lG?Gb?uQO2= zxnQc97IBmg3L%qU3kco!O=W6NnPtJHBJ@$vrYtTf3;F3E0eHqH8^u^>IbF~=GGMR3 z7T3T?w1>xNf}i0r<_nVS8Dl(w;;I745OSfTFFQZJzL_4pKl*&|bLZ3a)w|=jhsWC= z*PsZGGn$AnP7{_(W%L}RIS!oeb;S=rvg0kZ%9x%F(cnjR$*H`cK%8?utc~6(z z+w9-Gb-NdpWses_XkYZgFv$}chMjVx<^VOU0YVzds0k24!y@8h6T6tV;eOHv=zXKk zXX-fBkV(b>FxDNPEq&LYD+U(fQZq0nx_62x*+OHyik<@t6D_s@LYc!$5I8-2SvL+; zOkaGcIr)!W6C%5?#YHfEG)50S&FvnVpx5NF*{vx6ZQKl6PeVG)N}njwxuI+h3UXR; zRGT@#Q0`I+(-9Y0xje6dbp{&|^mI|25mWKfS*nIaEW_pO18BrGUx5X&>g`kf*H}S=^*+sh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o2DX#VV$tvLquv zFD5xZB{e44J3g%_Kd&Svv7jKPD8IBMwWv5IK0Y%qvm`!Vub}c4hfQvNN@-529mt^1 HK+FIDdDb6^ diff --git a/app/routers/__pycache__/user.cpython-312.pyc b/app/routers/__pycache__/user.cpython-312.pyc index d5846796e385f4ff100234c561bcb4d0003192dd..9c73c2c7a68464136680b8fe87645367a1a7d42a 100644 GIT binary patch delta 1442 zcmZ`&T}&KR6uxJEc4z-)*=1&T`6(9YF5LzLDN9)`0XI!k8(Op=m{gP!cC55m>dX*h zih`7AV@y-Li99q$n)t8?CQW=$Uu;N>G4W-{lCa&-_-cF_ev)d_7|)%hh@v;S=bpLW zckX=moOA!IzEdgx90+&`j=~q0F1{?!$}t$2ZRnkSFFF~}0+$Xj=$|9&(Rj^WftyR- zMXrQpeKTZnhju>rKXLy5hzn?CuX9;>M%axGJ&C3=#MLmOp*?6hL+SI7R9T#|2T|Tp zlM(s@41+*3-1Ko@ldg>pnImIYjHVG)L9c3z5PR@;Iy z9~-TB%5*Gq7;eiMAPdkbe5s)GJ>b?oKyMj5nK-}fjbsk;%Lhf~$9V+lkDkWMOs`Yd z0dz1wWRCn@zX`IqQ_FvMpp&sO6MM2WvRsy*Ah*e9+>)>_Z!xFdBK_R^9nVsA-WRWB zX~T;9aB*^meuDY+Xbkp}X~9?b%3*X)vYltqlzKHnqK&yz`ABN5EH!odzE3Ij#j!rC z|5dB+H7hl^Dqpaq3k9EI2@2*b)Vk9a!A6*cBf=*YjnJJ`>74)aWYMLMjpOqu@)tGJ zc^P^g{z+#oSmZ~pm^v$#&SdBzX2Q&rqj@B?-uA_cE~U)2;&Od97@$Mkya3^usIm?i(f=|l75&WV;{716B%hcwM-GueQ9d6^TIpl z-1|G{-rqU*-1m|1uL|*7hr@7 z55~?!$2D0QROHd9HWD8rzu=jKtu;Sw4dJw?$m)1}OqB=E#wB?)&F8@wF36h&n|_-f z5SNj*gH57^ZMzSJ@I*bpwg8OPxofL8zg}CIzxVdcPdDDVfBDO`_h(n%Tv}W5-839R zSmD7LR0$}RZW18H>{AJ6RFZZPSDb)5sACa`Y4p&Bgy4L8%HFJ-nm1tyU9j(@rMAZC zN`BBDFu0e4QOG@iSqAf304Xu@BU9A{tgJBq6e%uHN*RcB`RItM?INZsv?7$9O6ld8 zRj2F$-4rl_$$M-AZybLLA@U8|)-Z)9vFiAzgpx_(7TJ6g&HxI8%;ccyHYw%y@U+uI zjN&E7xF?%xU{XO3Ycmd87m?t|i2fw2@9$X=dv(4yBUWCCro;gGjPr0g1{rQ&j=^es+rWyw04%=g@g}04?1&n=tm12bLBy<)BoPT0Us&4w)2= zPVJX1@3#S}!r1!H-PWFusE-?;!VG)O;6p z{mx)~@K*$4-AsCgvJ*DM@NfAq`sZHKo5Iun6n-Ylm~e|8Y~MhjH(A7VVq+;QP*>kY z-`oqyI=%JT@0*TJ`%?J1b?~pDe$N|zHPFTH3SPGzm(8;q2o%M-0RuDZA-4c4!iSP& i8weD|`T+wo8z2t^Z>4}w<7DRsqMD+;c%7lPk?h}siHocN diff --git a/app/routers/__pycache__/user.cpython-38.pyc b/app/routers/__pycache__/user.cpython-38.pyc index 5762d61daf8a090457682909c3e42f7a116bbc4e..80fb1467fe4e30a99eeae5e99b4059cd1fd7a6fa 100644 GIT binary patch delta 999 zcmY*YO=uHA6rQ*Lo83(|Nt-s+v}sk^P@B+J5w+BdLiG?2T7?iOA+w}ENfTx_&_boy z7WC3Xon!SX^ehOTJ$sjx-aL5p;>CmbW)u3euy5wg_h!Ct-#7avbDEAXJ5G$?bNX(* zu^c~&Uxi;s)3o;R?SAvndD@4KG-!*XpYtU7@w0#;Y(73O|9pCsv7h&04V5 z-t}NT5akz>!KMK9|@DM`1&@6fb5gUgu)U*E{Q*oCl|{FUdZHjmGTUe6`l;R9U+lc+9VMeUBA8+x)dW?6~51!9z@z69h%3Ui9L?X5gP|VJ^R= zPCAYPHpD?hmgTGJ{T{~_KT-2D*8|u=laNa5Q!OAB+Dg?P)l2+dg#^+@j4}RO&GENJ z>eHA80BJt1&*%flU1mf4xqgjr>G{zSp~XDwa|qrgL7(-BTnS5jp_$k&*pk#2r-2JB z&;RJN{F`jdM~#@mqJZ=jV(+77pk^vjd50X64-!?*TB7n}gsM5j`~CU9OZ4Dn1XKOI`=U$O5WQxOSWvEt(;Yt{Us zaFl7d%yj-VHnuAcVx|b<2a6U-|59)28`qH+FZaakX^?E!0I2-6z?iETVf2gluNoMDxYW4cL$x zXe)|RWSIxSRnR9{L|^L5x-WwM5puydOBDoPd=e4Q+%z?d6Xuth^E-FW@0>aFbNanZ z>eXa2MsVEta(m~=_?=V{{=ReN=~3JEY#@vrRZ5BJC++y)hfhAb-&^Q3kMQ)a*c!b+IqIovM+(UxQT*%D+$M7_p z!!Oh9#(enceCV(+<*>jq=&;DLA)g8P+!UW?dE^VM81jp3=_V;Jt1Mhq6?iId28(sU zYd){m8?~O#MOE-t&2M%)>Lb`6#nva=^)du0!DX-8k-XaOGTyoeo-?8Api6c(^qS&) z0jG2jd@{uBFfjBl<2F{paq|A%lLz0Oe)ajUAMF2f|HI!t{`T~f!;^Q9Pmdpjd>Mp2 zLT539aE}NV|Ngr2;%23{>o>ZcN*yIsZoX9A7Tu0tsr7ml(d}abveK7ato3$-`5I&Y zODl=TNG*<-Vh(W-KTlDv*R_3WWQa~BOvA#3PY#GqLcKv(3#d=07V4UUS+uF|X*M~J zi%FogI-%|^c}S$|69$a3$PwKKA9Q*4UVJE+lRVjmU<=flX}e9$mtUU z8}Fds^5t|$H856_wgCxnK%*$AZ;WTHFrH9<7^T(asSwX#2<%g4>d-@Y4O23RPv44( zmbzvx%{Y7X9r`-CMLLMgIc}H+z=CR9PgogLAad#p>mqEaAFa}IQA>(Wnm`7?AJRqb zm8CMeNL^`SyO5ytOrr%Zh!yp`ef3rZIsM{(z$tGd3@(iuCag%w2VJQlxl2AftJg!K zD?s)rkU<{(uyTH6NDpA_t6nw>V5_g~`xI3-oy#MgK=V($)It8b5M5E)=6=1=?Cg}z zbJ#3xl?@R`M`0iY(d%#5c~8FxaRK+`h`6Y^l7>e#=*Ap_zWX4%!~OF|B&)Y~CoQ;1 zNRh}C`Vf0ug*gbTpr6E6IjeqmN;%KPPF|Ds25;Bon(ky_A}uVn5xp?7^)l?bs9x!! zg-Qc!-1~vi>qmY(UL|S`j*`k0DM4BC6tmv(dIi)?jw1#Ymn41>+yfM1$o*3@_A8;B;O17kWuAh5!Hn diff --git a/app/routers/user.py b/app/routers/user.py index c228a13..3780e77 100644 --- a/app/routers/user.py +++ b/app/routers/user.py @@ -1,8 +1,10 @@ from fastapi import APIRouter from typing import List from fastapi import APIRouter, HTTPException + +# from app.routers import get_cached_data from app.schemas.user import ChapterRelationCreate, ChapterRelationResponse -from app.services.user_service import create_chapter_relation, get_graph_relations, search_chapters, \ +from app.services.user_service import get_graph_relations, search_chapters, \ get_relations_to_level_simple, get_chapter_relations router = APIRouter( @@ -10,46 +12,55 @@ router = APIRouter( tags=["Chapters"], ) -@router.post("/relation/", response_model=ChapterRelationResponse) -def add_chapter_relation(relation: ChapterRelationCreate): - """ - 创建章节之间的关系 - """ - return create_chapter_relation(relation) @router.get("/relations/", response_model=List[ChapterRelationResponse]) -def list_chapter_relations(): +async def list_chapter_relations(): + # cache_key = "all_chapter_relations" + # cached_data = get_cached_data(cache_key) # 从缓存获取 + # if cached_data: + # return [ChapterRelationResponse(**data) for data in cached_data] # 缓存命中,返回数据 """ 查询所有章节关系 """ - return get_graph_relations() + return await get_graph_relations() @router.get("/search_chapters", response_model=List[ChapterRelationResponse]) -def search_chapters_endpoint(q: str): +async def search_chapters_endpoint(q: str): """ API 端点:根据搜索关键字模糊查询章节及其相关章节 :param q: 搜索关键字 :return: 匹配的章节关系列表 """ + # cache_key = f"search_chapters:{q}" + # # 尝试从缓存中获取数据 + # cached_data = get_cached_data(cache_key) + # if cached_data: + # # 如果缓存命中,直接返回缓存中的数据 + # return [ChapterRelationResponse(**data) for data in cached_data] if not q: raise HTTPException(status_code=400, detail="搜索关键字不能为空") - results = search_chapters(q) + results = await search_chapters(q) if not results: raise HTTPException(status_code=404, detail="未找到匹配的章节关系") return results @router.get("/relations/level/{level}", response_model=List[ChapterRelationResponse]) -def get_relations_by_level_simple(level: int): +async def get_relations_by_level_simple(level: int): """ 简化版:根据目标层级查询从 Root 到目标层级的所有节点和关系 :param level: 目标层级(1 -> Root & Subject, 2 -> Root, Subject, Topic, ..., 5 -> Problem) :return: 对应层级的节点和关系 """ + # cache_key = f"level_{level}_relations" + # cached_data = get_cached_data(cache_key) # 从缓存获取 + # if cached_data: + # return [ChapterRelationResponse(**data) for data in cached_data] # 缓存命中,返回数据 + if level < 0 or level > 5: raise HTTPException(status_code=400, detail="层级参数必须在 0 到 5 之间") try: - relations = get_relations_to_level_simple(level) + relations = await get_relations_to_level_simple(level) if not relations: raise HTTPException(status_code=404, detail="未找到相关节点关系") return relations @@ -62,10 +73,11 @@ async def get_relations_by_chapter(chapter: str): :param chapter_name: 章节名称 :return: 章节关系列表 """ - try: - relations = get_chapter_relations(chapter) - if not relations: - raise HTTPException(status_code=404, detail=f"No relations found for chapter {chapter}") - return relations - except Exception as e: - raise HTTPException(status_code=500, detail=f"Error fetching relations: {str(e)}") \ No newline at end of file + # cache_key = f"chapter_relations:{chapter}" # 不使用分页,直接根据章节名称生成缓存键 + # cached_data = get_cached_data(cache_key) # 从缓存中获取数据 + # if cached_data: + # return [ChapterRelationResponse(**data) for data in cached_data] # 如果缓存命中,直接返回缓存数据 + relations = await get_chapter_relations(chapter) + if not relations: + raise HTTPException(status_code=404, detail=f"No relations found for chapter {chapter}") + return relations \ No newline at end of file diff --git a/app/schemas/__pycache__/__init__.cpython-312.pyc b/app/schemas/__pycache__/__init__.cpython-312.pyc index 4d300f40ea951457a1bde54f853641f2719ccfe3..c89635a6fdcdd44dfb481a2440658fe72b8b9305 100644 GIT binary patch delta 19 ZcmbQqIFph4G%qg~0}#xKa-GQC2LLPp1e5>( delta 19 ZcmbQqIFph4G%qg~0}vR#N}I^t2LLS61lj-q diff --git a/app/schemas/__pycache__/__init__.cpython-38.pyc b/app/schemas/__pycache__/__init__.cpython-38.pyc index 6b1be78293fb5b56dac6d0e573ef926737d5b87d..b4082ffa02f79f65234979e3c538d5a32ba9b858 100644 GIT binary patch delta 31 mcmeBTY-gO{E~?{V6;n`Il98VmlboND8k3!FXk|&hYE}`#Y6;n`Il98VmlboND8WZdtpH`HgS28h18vx2x3_kz> diff --git a/app/schemas/__pycache__/user.cpython-312.pyc b/app/schemas/__pycache__/user.cpython-312.pyc index 610de8f856d01e9c65583f7f9c4b7305bbe40892..ee0324f8087017870ad683c3f9108f77f98da09b 100644 GIT binary patch delta 20 acmbQvKAoNWG%qg~0}!aMOx(!b!wdj0(gd>r delta 20 acmbQvKAoNWG%qg~0}vR#O54cY!wdj2w*>|mVWE~@Kd6;n`Il98VmlboND8k3!FXk}H(cE@9we6;n`Il98VmlboND8WZdtpH`HgS28h12LQ^m3_}0_ diff --git a/app/services/__pycache__/user_service.cpython-312.pyc b/app/services/__pycache__/user_service.cpython-312.pyc index 1d39e6bac959376b8709cd17750c8f5a5c5515c2..ae78e77bffe9a99cbce65ffb062f018e512f910e 100644 GIT binary patch delta 4018 zcmd5%mBrI=JrD>HqY15pKDI~45opTKV zGNNw(&FG!`yXT&B&wadee($`gmMd+RkIiNSf#1V0i^#9&x=ay6)Vx7!1g#}vdcxKW+N@C;u>2K+bp~ik zx35o)!DwzjeE49?i`~(oSl_9^0KG8ttfw1|R)2WBvvA!Tr-XD6s$CW;ZMEbqjc{W; zAwS?Q@~;Yl_OVcsb(XB?_>AuFg6}_cX0cG)E_$-Zg@}YVazlSz$b^~@HJd$0Q$*)C zxd{AS=Q8@UfY(JLlpG@UE*CIy{JK%II)6uU8w?wL~2luty0G^&Ve6sH)_{Iv!2^9f;4!@=GLb(3|xywcNK8 zYu-|pe<91im{tCOI0SbZ#kKmRtMKC3g|Vx3i>|xLxk<|c#@Ok3-QRAoonn5sI=RqeFLrA-=lxVZ`Gv~&pW3da#TLLO)F-;70EZKqNI z&*dGOG7N>4@IW*cRa9kT7N^$bv0?#hEodomVmd2XD6A-KC?svrQWnPz6$grJ6iyU5 zC~{G_K%{6?)x+pr`6+p*%u=IarMvfdcW-!z9pfvY-3FKH1>(r0sl|Y4n$B?u_CGp2 zOOC*TBe3YGctEmbPa4Iwk+Nid@#L;cyRHtuUpbdQ-|&qe?pn-0vgAB+t~FUuJlS!n zsaO=~eA*>()#u35-)$O6m7j#@-p-N}X8jtadi&a%@2=YWr2)aimYt^u~N3e7`|aPDO*Ygd8|!w zgu+I=_8Uiy7IWkt6;=wEjcWzWLRf(h{t4G78$$Jdd8koA`^a&?{gl1o6<3n|b{{JoQO%OO=5;aYEqmMertwGSr9AB??tRY`UjcBUp8s{61A<=X#IlG=9nvc8#br4my+(D5JQHcF8>8^R0%&Yty=qA^mmO%w{ z1Cj|aG}|BD(dP5E`5&dr!0Tbs*|kbf*+5UALVMYg*;s4z6gI3@CkWoK)UpDLuS0dcCxg*ZrCw~ABsdc@Dww^obOK@RZr4infXbhNcr zOb9x}vJtjSICI;*BvDD*8pT8vkGRI&ZscbSw4I1EMpqms#k8FhXG-*lEB2JP>%>_* z2b0-s6L`#eX}c`W`gDl>6n330qYz;>Kq2z%Rwk~7lnoN2aE0(?s+ zf&DEb2fnw=a@$V+R*t)^j=xn+<2czS;6j~%cqfmzkwUOJLg5f|9FsZ$vCQ;FvE3uh z*=T#VY0fSocH^zh72x6KJPdo~y=Hzc;NGj}Z*vszZ62fC)(eQu7$qfj_ZG7^*XI0s zm_bsO2%C%X;Pb|eAQMiL18`sjSaek6g;C1>YG5;)hEwrdCTqO}q@JwVU9D4^@; z%#<}JLs{b@l=Z5~9Ymks&(oTH5SouIG*oFyR7f~^ z2E!)mm~)Wf2D!P6pW)oiK7J;jA}$bM>lvSbxQquJurl&biLue4zQG;^KK)2aIuTZ5 z;h{bSUWz1Tf)Ai7{2uytSdC^rn5?K$yL;o&fv{RN3~EILQ})5czGG6n8dDT(6;piQ zU`#>&SMXWBL+*hj?3q8(?;bc68Salht2BWQ9xzc)f=Kg}(mxQ(pNQ*I;`@}8d_p?z z8hq59Zl``~zpADQ4A)}wwJjYB)%)(@EPar+Qc%JgjyGfTyALhYAHK(C=}yiIYmPL5 U;b!)HaQ{M0=Y5Vj0r*0{PVG5=F@MZU{**bk>NH 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 literal 6309 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 Qq*hnU8c*Ab_7yMx2bVM?EdT%j diff --git a/app/services/user_service.py b/app/services/user_service.py index 982897b..932d71d 100644 --- a/app/services/user_service.py +++ b/app/services/user_service.py @@ -1,39 +1,15 @@ import logging from typing import List +from fastapi import HTTPException + from app.database import neo4j_conn from app.schemas.user import ChapterRelationCreate, ChapterRelationResponse -def create_chapter_relation(relation_data: ChapterRelationCreate): - """ - 创建章节关系 - :param relation_data: 包含起始章节、结束章节和关系类型 - :return: 创建的关系数据 - """ - query = """ - MERGE (start:Chapter {name: $start_chapter}) - MERGE (end:Chapter {name: $end_chapter}) - CREATE (start)-[r:%s]->(end) - RETURN start.name AS start_chapter, TYPE(r) AS relation, end.name AS end_chapter - """ % relation_data.relation.upper() # 使用动态关系类型 - - # 获取 session 进行查询 - with neo4j_conn.get_session() as session: - result = session.run(query, parameters={ - "start_chapter": relation_data.start_chapter, - "end_chapter": relation_data.end_chapter, - }) - record = result.single() - return { - "start_chapter": record["start_chapter"], - "relation": record["relation"], - "end_chapter": record["end_chapter"], - } - - - -def get_graph_relations(): + + +async def get_graph_relations(): """ 查询知识图谱中的所有节点及关系的详细信息 :return: 列表,每一项为 ChapterRelationResponse 对象 @@ -47,9 +23,9 @@ def get_graph_relations(): properties(end) AS end_properties, labels(end) AS end_labels """ - with neo4j_conn.get_session() as session: - result = session.run(query) - records = result.data() + async with neo4j_conn.get_session() as session: + result = await session.run(query) + records = await result.data() responses = [] for record in records: @@ -69,7 +45,7 @@ def get_graph_relations(): return responses -def search_chapters(search_term: str) -> List[ChapterRelationResponse]: +async def search_chapters(search_term: str) -> List[ChapterRelationResponse]: """ 根据搜索关键字模糊查询章节及其相关章节 :param search_term: 搜索关键字 @@ -88,9 +64,9 @@ def search_chapters(search_term: str) -> List[ChapterRelationResponse]: labels(end) AS end_labels """ try: - with neo4j_conn.get_session() as session: - result = session.run(query, parameters={"search_term": search_term}) - records = result.data() + async with neo4j_conn.get_session() as session: + result = await session.run(query, parameters={"search_term": search_term}) + records = await result.data() responses = [ ChapterRelationResponse( @@ -109,7 +85,7 @@ def search_chapters(search_term: str) -> List[ChapterRelationResponse]: return [] -def get_relations_to_level_simple(level: int) -> List[ChapterRelationResponse]: +async def get_relations_to_level_simple(level: int) -> List[ChapterRelationResponse]: """ 简化版:根据目标层级查询从 Root 到目标层级的所有节点和关系 :param level: 目标层级(1 -> Root & Subject, 2 -> Root, Subject, Topic, ..., 5 -> Problem) @@ -130,9 +106,9 @@ def get_relations_to_level_simple(level: int) -> List[ChapterRelationResponse]: """ try: - with neo4j_conn.get_session() as session: - result = session.run(query) - records = result.data() + async with neo4j_conn.get_session() as session: + result = await session.run(query) + records = await result.data() return [ ChapterRelationResponse( @@ -163,9 +139,9 @@ def get_relations_to_level_simple(level: int) -> List[ChapterRelationResponse]: """ try: - with neo4j_conn.get_session() as session: - result = session.run(query, parameters={"target_labels": target_labels}) - records = result.data() + async with neo4j_conn.get_session() as session: + result = await session.run(query, parameters={"target_labels": target_labels}) + records = await result.data() return [ ChapterRelationResponse( @@ -180,7 +156,7 @@ def get_relations_to_level_simple(level: int) -> List[ChapterRelationResponse]: except Exception as e: logging.error(f"Error during get_relations_to_level_simple: {e}") return [] -def get_chapter_relations(chapter: str) -> List[ChapterRelationResponse]: +async def get_chapter_relations(chapter: str) -> List[ChapterRelationResponse]: """ 根据章节名称查找该章节及其相关节点和关系 :param chapter_name: 章节名称 @@ -197,10 +173,9 @@ def get_chapter_relations(chapter: str) -> List[ChapterRelationResponse]: labels(end) AS end_labels """ try: - with neo4j_conn.get_session() as session: - result = session.run(query, parameters={"chapter": chapter}) - records = result.data() - + async with neo4j_conn.get_session() as session: + result = await session.run(query, parameters={"chapter": chapter}) + records = await result.data() return [ ChapterRelationResponse( start_labels=record.get("start_labels", []), diff --git a/app/test/__init__.py b/app/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/test/__pycache__/__init__.cpython-38.pyc b/app/test/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d075c36371c1d5d8017b2608380628a68a63c37a GIT binary patch literal 132 zcmWIL<>g`kg0&4<=^*+sh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o2DL#VV$tvLquv zFD5xZB{e2H-O$K5Cb6I(rX;nvBqlySGcU6wK3=b&@)n0pZhlH>PO2Tqh|fUG006`! B9MAv& literal 0 HcmV?d00001 diff --git a/app/test/__pycache__/test.cpython-38-pytest-8.3.3.pyc b/app/test/__pycache__/test.cpython-38-pytest-8.3.3.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8be3e39bc99800e8de4d72665f6cdf7a7fafefac GIT binary patch literal 7017 zcmeHLU2Ggz6`ngYJ3Bl3Z#yA%(z2lq%|fxg{)-*zkiV9KgegV*XccKS@g3W{9`7!9 z#-TPd2*p&Ygjy^VRFtNY%?tGdsE9liBjAA-o)C{{UU(pG>Q~e!KUAD^XLfhS*>w{V zq$1VUp1D6~?%&+=o$s7)rPG=Ke}DQ#ZQ-9#`WIHhe-c#A!_V3QK?O=op-lKwT$V(E z2+MLgM*JS7tni+AInJMIS>?|}IRQ`6)RvRwBoT~6EmccXiON3~)=4=N)MHfP^=wd& zQhBu(*pUrJS^d}s$MVJjG4NG+q`mro-5&ncZsCr8} zD!4HU8+T$=0%gTcLT}1Zw#YiU4xd35ToHaaKdGhNxD#I&T*=NjlAT=_UDZ)Hh*hU> zRPEW{hY=EX24?>^&V(hHJ=Iwsypcg2T-OF+$51P>#&~Fr>DIXL)@43&mcKR2$A&VD zo#rE`u%pZ^1$L1Lc996}A`ZKdT=hG`gz$~v#9tD=3nvesE<3xQT(s@x+2LW^uQ&t`Dl5!f8yKEj)SI@!tYK!Dx?OG5t>L}Dg3>nG7iVU+$=cYd)6LbLzb=ED^_K$K@H6<%=jG>Maxr}VKreaV_Whh&_ywdVq!m|Tb99WKE@eP zg~l`c^P$G6)?85N%yk;)grWUqKq2TFYc)Y3Xezls)2ddr z4y&%u8J=ub;Ybvggx%sQN+`xyI;c)!b*h;2Vt9ftd&vvdYJKjKSvBf5KSoblFl;Xw zIs;ET-(1CmuIS9mSLSrntT3a=<{HaQof%#Vx+_;#s-_K#@D#HF8kTpgVl6gSOv+U& z3ufc0ZdU60vf(8vmOgLb2wvs_KQ;J1&oS0uUVml2!IpKqV!Yfm^*aA@o{YO@dDsB! z15wmGWzJu30ymY!>HUK)g)8IX%9vmAN1qH=row8Y;mVn?+Vr--hG4q=QM}-s&||p7=DXNa2Meqf~%;)IM!!C2;v~g5e2MPh2N}@ z5;8&x>I%S*B5Xj7jeu4JoU+i+2B#Wa{I1|6-n{q;IB}TyAA(Z^VsnnPPF#&<-K3*A z$tBrMIjIfNx(KUKXwFFi_~)^QgMVKLCjSN+2|LGO@*lWnECWpTMIiVC)CwT@L)7X8 z!MslkAUO#j+s{EZO$X=^C(YePCIDQ3`nKEPfD53j!7t?|y8`dgS%&VP$spDq?|`gj z=xlDWb>ndj4aNX`&+n;gXSHRSD29*@*)Q^l8^u!7`Bs zs(=J(?1|DqAWSl7v}_zHSJcK^R8S6V8;}hMl#Dcx0=IP(Zrk0+6sLq>*Qy)uYS;O& zU7tA2uJ<l|*@oPlt=NyClxq7eEaRQVXRq)E!--6f@Fvy{ zZ?X{HsGg0d_ZtI)QI}3bi6@LQ@b#T&PqJKl00V+clb)6959HMmS_p6 z#dj$(4YhjhlJ_BlK%HI;!r#+FF^J-fRlz!AK$GOHXp!hPbK|15~cAR`^zZmx?UG!dHC* zN4MEKDCp``zYOn2O#Tz63b~b!i&H)1s!y^n!lygjr?O{3Wd-l%?r*Q(-TBq-Pp`lC z^LKXt{L0?eA9ioOT^K3szWPpKqHyQ;KiPZZHk-i#&!ISv;sT0`C@!Hma5~aSF z2N~#t_@5U*KXMr{8_{NXJDlNd5=^LJ){n*(Vq3%&Y_TTUGF50il4koMrqwoMRCRaV<-tYRt)ABYjNa!$OP@Y zBinu8n-Wd}F5^v_r+uy2p+11~+dgtXfwN(mBX@g^pmi3taBYx&yNp_qb%LkiZMe?< z(AZ6U%kJZEt)T{%VeEdc4c>?j@W@aLb^?gs-iZo3k=;aBws>ULBPEZFd1TTfQ)RI< z5sC`64yLbZo$T9x3FpOrPhonUHkKjhv)HK48Qrj(J&)J=A&|S6ENiVSO_kmcxr>Hh z_i0kCDLAD=D-29(fDDpjq&Mc@z(mm351Ld2-`9EvO)vdlQM$tdsBZ%yL85sufND`3 zV&y=iMdXmwMJY~;Y+?X~eZ2yxd+FK(1yDyjCQusbm_YT$M}|%u=GRWnHVSP%RG4q9 z)G0_-2(C||G|~;=i`hqM8r>Yl)7>3K>sHqrHe_#Mu}HEkOjjJnWg_9qi=bOP;;F49 zGEbU#k5&A%^N^o?fh6$|GrrHNHl&c-Or axAixz3Vnh~_`jGE6{0Ediw94&^ZXAZxq$xw literal 0 HcmV?d00001 diff --git a/app/test/test.py b/app/test/test.py new file mode 100644 index 0000000..5ce98a1 --- /dev/null +++ b/app/test/test.py @@ -0,0 +1,61 @@ +import logging +import random +import httpx +import pytest # 使用 pytest 来运行异步测试 + +from app.main import app # 替换为你的 FastAPI 应用实例 + +@pytest.mark.asyncio # 指定测试是异步的 +async def test_list_chapter_relations(): + async with httpx.AsyncClient(app=app, base_url="http://test") as client: + response = await client.get("/chapters/relations/") + assert response.status_code == 200 + assert isinstance(response.json(), list) # 检查返回的数据类型 + +@pytest.mark.asyncio +async def test_search_chapters_valid(): + async with httpx.AsyncClient(app=app, base_url="http://test") as client: + response = await client.get("/chapters/search_chapters?q=1") + assert response.status_code == 200 + assert isinstance(response.json(), list) + assert len(response.json()) > 0 # 假设数据库中有相关数据 + +@pytest.mark.asyncio +async def test_search_chapters_invalid(): + async with httpx.AsyncClient(app=app, base_url="http://test") as client: + response = await client.get("/chapters/search_chapters?q=") # 空查询 + assert response.status_code == 400 + assert response.json() == {"detail": "搜索关键字不能为空"} + +@pytest.mark.asyncio +async def test_get_relations_by_level_valid(): + async with httpx.AsyncClient(app=app, base_url="http://test") as client: + response = await client.get("/chapters/relations/level/3") + print(response.json()) + assert response.status_code == 200 + assert isinstance(response.json(), list) + assert len(response.json()) > 0 + +@pytest.mark.asyncio +async def test_get_relations_by_level_invalid(): + async with httpx.AsyncClient(app=app, base_url="http://test") as client: + response = await client.get("/chapters/relations/level/6") + assert response.status_code == 400 + assert response.json() == {"detail": "层级参数必须在 0 到 5 之间"} + +@pytest.mark.asyncio +async def test_get_relations_by_chapter_valid(): + chapter_id = random.choice(["1", "3", "6", "8", "15"]) + async with httpx.AsyncClient(app=app, base_url="http://test") as client: + response = await client.get(f"/chapters/{chapter_id}/relations") + print(response.json()) + assert response.status_code == 200 + assert isinstance(response.json(), list) + +@pytest.mark.asyncio +async def test_get_relations_by_chapter_not_found(): + async with httpx.AsyncClient(app=app, base_url="http://test") as client: + response = await client.get("/chapters/10/relations") + print(response.json()) + assert response.status_code == 404 + assert response.json() == {"detail": "No relations found for chapter 10"}