From 1b4a2686e7ffc0d92356521db5aa0da6309e075b Mon Sep 17 00:00:00 2001 From: Janaina <jsk22@inf.ufpr.br> Date: Wed, 26 Feb 2025 10:24:40 -0300 Subject: [PATCH] Issue #47/CREATE-collect-users-table --- bun.lockb | Bin 74415 -> 76818 bytes ...ne_men.sql => 0000_flawless_scarecrow.sql} | 24 + .../migrations/0000_secret_sharon_ventura.sql | 588 ---- src/db/migrations/0001_odd_valkyrie.sql | 18 + src/db/migrations/0001_strange_famine.sql | 1 - .../migrations/0002_sleepy_vin_gonzales.sql | 1 - src/db/migrations/0004_useful_paper_doll.sql | 22 - src/db/migrations/0005_eager_darkstar.sql | 1 - ...{0005_snapshot.json => 0000_snapshot.json} | 4 +- ...{0004_snapshot.json => 0001_snapshot.json} | 74 +- src/db/migrations/meta/0003_snapshot.json | 2523 ----------------- src/db/migrations/meta/_journal.json | 36 +- src/db/relations/user-collection.relation.ts | 47 + src/db/repo/collections.repo.ts | 13 + src/db/repo/user-collection.repo.ts | 123 + src/db/schema/index.ts | 8 +- src/db/seed.ts | 3 +- src/db/seeds/collection-stats.seed.ts | 1 + src/db/seeds/index.ts | 5 +- src/db/seeds/resource-language.seed.ts | 4 +- src/db/seeds/user-collection.seed.ts | 38 + src/db/seeds/user-stats.seed.ts | 1 - src/index.ts | 3 + src/routes/user-collection.route.ts | 120 + src/services/user-collection.service.ts | 30 + 25 files changed, 507 insertions(+), 3181 deletions(-) rename src/db/migrations/{0003_tired_stone_men.sql => 0000_flawless_scarecrow.sql} (96%) delete mode 100644 src/db/migrations/0000_secret_sharon_ventura.sql create mode 100644 src/db/migrations/0001_odd_valkyrie.sql delete mode 100644 src/db/migrations/0001_strange_famine.sql delete mode 100644 src/db/migrations/0002_sleepy_vin_gonzales.sql delete mode 100644 src/db/migrations/0004_useful_paper_doll.sql delete mode 100644 src/db/migrations/0005_eager_darkstar.sql rename src/db/migrations/meta/{0005_snapshot.json => 0000_snapshot.json} (99%) rename src/db/migrations/meta/{0004_snapshot.json => 0001_snapshot.json} (97%) delete mode 100644 src/db/migrations/meta/0003_snapshot.json create mode 100644 src/db/relations/user-collection.relation.ts create mode 100644 src/db/repo/user-collection.repo.ts create mode 100644 src/db/seeds/user-collection.seed.ts create mode 100644 src/routes/user-collection.route.ts create mode 100644 src/services/user-collection.service.ts diff --git a/bun.lockb b/bun.lockb index 541186b4a229c7a1084630a8380ec367adcb78ba..eb973bacbb595524c04f0abd0000e6b6fc16a0d4 100755 GIT binary patch delta 13955 zcmZ2~lx5NlmI->AF<W1+X!%rA5o8kH*^*SEv68(oy`|xgNUMGJZq3e=vL<at1`s$g zF<hQW<JiOsh5Ahl3=9Gc3=IYO#U<%Qsl^%jdHEnE%NZCLxEUB4=0NFw1_lOR28M=| z{F2nXG6sek1_lOU28M=g1_lN}28IS0e<lk9gB$}xLoh2ue`R8B4#>P{s6Ad#^{K@< znRz7)^$cko3=CWh3=J_*`UR8@g3|4r5C`U@mgRvAs^x^J&w|n=oD2+{Acv)<7U*Uc zGdOcFFz_=lG+1#!#LKxM{M+0ReP_8D82A_%8uU0A7<d@!85%e_7#LI;7#e=FLnJbb zb<=b5lNcuQLNt6}hxjBjJukl~m4V?Yl%JNFm!ex*z;J>OBEJ_(7wG2XCnuJq7U<?= z=4O^K?B$2ZUuB1Q#7_WXZgy&A8ACk-1H%ykh=R17#FCQK6ozB$5ErKwmzHGa6f>k2 z7nY_LRWf`PglJ4HE+|S(WnkFM4vB&SA&5^Clk<x}LA0D5<THkb>B124$?OaaBH$28 zDotl#V8|^7g(Cw)2Rj2p7$}a*GcuDi7#J8bi&HC785kIji9j4MQxp>C1&JjYy4k6f z$r*_`p!kjzgM?H@VzF*oPGWkH7{mjr;t=&E;*)nV$<;GUK<s@f&cGnWz|c?u4S=-7 z;*vrJ28N>4(&EgtN`^d1h(GM5Anxv#f>^IF1qrYesQca6AxVpe0TK>oQ1eV>Ao{b4 zb-}4Eu_(PDv8cE{RZ|9HV7x4Z4w8kq@2xB(U_jBFm{ZK41hrs;90P+W149ERI|G9x z14F}WHi(6=fbL>rU{GLSXeeZZ$Xh8gFsLvvG|X0DV322EXi!pQV31&7Xed$u*(bu# zFii>KQbbyu{EAtv{-rX+{z)nj=^H8#eo|3la%wRHgTE?7e5xuWoS&;g<Y6f<C9?>e zL>H(*#P2CX!he?n#C>%N3=Fai3=NTN5cgy%K-3i!rIwUrrcUl>k*qJ)WMB|yU}$)y z334k#gP9g2urEW!uWK<d2r)1;IBG-OVx|qTBegiGG&3iKVWloa|72YT1~CSPhFU0{ z4y6O3w2dw#Of_^Ni9rNH*EcXg7!7Z9AQCsA^bsh%0ZPw-(w#bxST2Lo$xu1~O55o` z9IOMSrJytilup)!co5=&dWwBOnFmrC7#c|RLB9#ahYAdk=oEwIgH$F6U&aO!MTs_$ zC>6Gu+{G4WkjmRW?YLotUZIHDjBYv3-Yx#OOJq#<7^`aSxEHgqfZgO5&))E<8{;<o zJ~!v)@7|cjFWA@^4^4i_W6$_;vL>%RquS(5UVFy8$t!v78JA6d$!pJeZL%hxJ(Dcc z<Safr#wn9m^4T+9pZt=~o{5KLau%;0ZwLzmgDV3=1E`!4np`NTJ^29-2j_Mc1_lq1 z=;V#6=A8do7#Knr7#i3o8%mmU#<4Om*fB6PuuLu#H0Pbe%D`a2z|g?Nz`(#hc_9x( z{~1;W1}Ct7LnRAFw#ixic1+vZCa>bRV=Ca7{EFX>X${9@Ede{uPaF&kHVh06tdk7| z%$f8!C$AE)<DAY3v7Kr1Mm}?<`<#=t1nrpkxh7``+A(=^O<pBv$JEX>`IVp@(?PDu zT0(Z5-?<nV+!z=d7(q^AvgMw<O303>jeGJdAv?~e+z=ZWz&0rIOwJOvV@l<jyh_-P zb14r4LlIb?p@0P=?_@0zJI-ic1_m>*_Y6hMnP&4&UL|73dYzYn!EUmykTsJi-()RO zJ5EnNNFcCHE)+KBZ0CdMVV(R@)ST%u-{e=KcASFzFeM*F%{l$~85k_U9tA0B=byYv z%#QN}R0+f6jbi4UYyuE(bAU|Yj1Yjhn+5FdDFTyMiQ93W7l4?_3=-tz6@*yJJlRmx zoXJ^ma+ZW0XD3vUX|kb+Ip=;Tk8$!wesiY(f|Io*?KrK47#K_$7#g@h*0NR#F);W| zek*FtbX;iiD@i*h72(NRQg)o-!VC-!3=9n%V7nFwGcZ^|f<@At^_DOLLjYKhmdIo+ zX*<ps5e5bwP%@ajQOKOLLj>YXcCZ`Xi!d-4f#pD9r6>yHfr2Gi6cTexU_UPtg(Mqh zFz<yZB*>U2Zxk`-R1kycV*%TcEylp$0#1@2`OR6^i!m@*fSkkmTnu6}3plA7i9^g| z0(+rO91^08lMRK;nRba!UL|M8DK5dlU;^=%pgE_v1jI@vP>8ZNOMrZ-D`?GmS%QHf z2JD56V&+Wxl9OM_+c7mtPS#SeW7;A)IZMHg>6PT<RSI^T-cpcIW1Rev-<)Zd)MPD1 zJEjLxld}}<IOU}o7#tzFLehdmnt>q{n)b|@wn~FC2kT2|1_p=8YsIWNJ!BXd{1_M- zAf8_$1Bq!CP>gZjl7YKYz?@S^7Gfha$jhwRARag<R?9*>&j|87>o-{j1}m`1267Ax z<_ruCe4s#PN|&3wO2v-zs2l@>7ubWKu;G`Vtfgwl86nTW5CjgJLP2w;qw<qisoJp$ zD=;vGP0r=FX1%4rz~BL9#VIl{#DQ6R6d4#oz$^hJ1_n0}i!)3K;y^}_1DVz+P0muc z<9wk6Nl%=U3l+>cm6T!0z)--Pvs4)pC+w3q3Y&ATREDHhZm{1!DMOM0B#Ee~KvXhL zHWW1Hj8K7?$vpX^q&d?ZmC0F}cAO8Pf{-YcR%Ku?nXD^f%^9f*Ne%4a)U{X@lAgfj z5a$O~h(YY2AmY?ggQO`|aLUV2g9JV}3$m_M0|o0_QESe}P*qGIXR<1)!$PTC9h8Vb z;dNXc79zYF5c9$16=%2x%tVm0`!yzO>DqB#(14V=oFL<vR5T~A(zRpi(wzKC*N*9% z=435BJ5Dz(NO{2sc4eOy1A`|x!GKJ8sWthPo*k37_GB%6JI;1(hz}S+K47|_J$aSB z9qR#I1_uAhYxS*J`SlnWd?)9c*sy>ZAfc6T);BoIS)YNyd-7XD8%F)fT1NJa`jfMa z>=_LvuL6^=z@(P3J&OSYgD2Qr7eg4U7tXq7$iUzZmX$Svu~Oiy)o|7)BL)UnusU;N z7^?=(ItXKNvY9{vff-!Dg_}%XWopN|&;;x?Q)|`_CSb2w*|3;`7;8<fS-aq@>u{Ee z8Q5#)HjHMIwJhuz%_e7A*fW|>UIiv!fk`b(dlqxBhfJ+mRV`qwJUDB+1=vHT)~x^F zELTgISPz_a*%Is_Q)^ZUD;O&l&RPU#J%_P4Gp!-%1yY_awuWQ~#>pEM%$aUjPu8-r zV^X)7oMmIjlxs72m5m+KI-AL_Y^>@<8Ne+%P~8q{Efb_cmAE(qxC_8w$iTn=>Vg`9 zb%8S-14!P4fq{XA0i0sNd@BY9Fl_@>Zwpm#%fL_%Hoy+5!HI!^L5YEZAqA=cM1w2< zbz?w6AexPVfdSNQ0r5dJ$iiHx!Jz&UNE{yxG7r=z2I(t=nFQ*<fHdNxK^ludia?zm zEHp?S)E5I8Tnd#3(ID|MkOL>*wUe(0$yS4S43J(oNFk`Vjf)29t_4XlFff2<W(H90 z01*JS$UyRq5H16V2ASUsHNOQa4x&NoT0!9r5^H5(U;r7^0ae%u5@cXt0MQ_YT~IzU z4Kla~s=gO0528Wp`=H{WVFi#Bhz2Eq$x!hrAVCHOhAH44GME7o0ZD)io(5Go9U{yC zqCw&_q2jZk;>6IL3=9m5q3S_2$bn0s{3W0sI>_K<PyrAPQm`D#N2Wm`v<fPYOoQ~V zfr^7@ZUzR1?F<YIpp?0nfq{X8fq~&DG|3-_ssqs=d+JX>1wb@N;3U+Cr=a2>8f4G~ zC?A<-Wnf^q3N`pTR31cw%(($I=O&cC1(gTUAo<%6@yYUzqTn=mkAZ;!WZq*a{Q{~U z8x7L`5}IV*K<$4AF^}OrR3C^21<XgN{AZ{*G7akDa56&E04K;)P~V5{G$;*_XfeoV z+>GEpGJ_J-!DQ3*lo~*RevsCBWkyK3t-=T?m(`$rb&xCr0|SVLGQo8MsEz<dCowcA zqzKdx^`O=?u@wXj>W6v;2I4CSkiQui@YM?-6(D&~h!IskNH8!kfGP%%Mi33sI9fq~ zLSwXoU>L0+Mk|Pct{@Z%RuG#lJ)bZ;ytsHq*1t+l_8WUlbL;+!^tQ@BpV!Rr-o{uJ zrkl>V`r7JEF6kDh%iho3B-HwX!L%mQLFP@Z$AoJWWHP><x_Uc#a;&dJ{gDoy#DY)i zjgMcxRQqZlaeKGPXXn%}SC1FW<lE<ZzU|pLJ$uD8=k8Avp3g0R&-t%Vz+d1|Giz0e zNa_@qz}^Kb!FAU^{(p?%*#K}U0wP%6U9?{xA%5VHzEtVez)M;|0#mMvuNMf|q2|}P z>$KFxpQe?^p3iAckxaMvD)4~wg#Vd4OlD6kkNf{Q<*>J2<YUsu$-I6N^<P&Do5*`i zSZEw^oPB1P%Uf&n3Hokt7~Sj6E4@9|{Gsf``xPv`H#y3C{xdoMxi22Mq3*m6=kvTc z>y<ObcS|{}M{*rM$XQU#@=IjJ=`ZZl-lTEgWKx*Z{qIfdjGc3SzH<_l3(J1?Qb|bp z^Q5c!*W4v<m8P%S_`>Vcie~2K{SHf4&Q$AEnWa$Y?K63=pM;NLnuOQ?6z)R?B0@LI zIV4k#{5|Wnjr*T{mG>sW<|Q&7B1WtCiR9j^-0hg&C2u6R<!DQxt88N<;|h}|?o;Q_ ziy^sAaI&Cp_~Z(I-pQrD-i*SN5Bi2r)(GI8tm@~@C_1^&FMRTi0N%-0{k$2)CoB4g zPwoiho!sj0%_uqfqJQ{giy+>~rUBlJ(vuql!Y987;+_07z?)HavSDEO<Qc)dlcxrH zGs;hX7#Kd;BZPOdYmhgi;^c`z;gf%a@J{|3<jtr&*)ceL@`_O2$xDO18C55L3=W?h z5ym??G{l=xee%MP@W~wEypvf&y%{wp2Zn}E-Vx3_d26UQqxNLRu<*$l5xkRA!@L=F zCvOZ3pDYo{J6SZ`n^AvqVtDxE6Op`=kA{0Q8cr6B2%lUL#XGq)!kf`}^1+Dk$r{nT zlT{<V8BHe_Mutzm5zRaKYNR)#`DDeY@W~x9ypvm_ycsPgUyKT$Y!S;l*)-al(Ry-Y zbok^KvAmO?Mtd{bPBx4QpFAUuck<L2Z$|sc4`ae7d&Kijc8&FBbeudfHhl7rc;3lh zW4#%jCp*T4PhOG0J9%lGH>2z1k8$CXBNBNhhsJv|x=&shA3m8QiFYz<f;Xe*<iLdR z$vcvGCvQ#gX7rxSm>51eBbj${YN9uz@8pe%;gcm&cqfY{c{BP?PD~1)d?JN+^3f!3 z#=yyf$>EbLQh6trCVMjmPd=C&K3OA;cd}}VH)H7J!j$mIH_~_~Urq6544<r+8a}xr zop*9;syAcg<cq1{lPxlMC!3~uGe%EtObeg<B7=AG(=>0!*vW?J;ge@%@=l(b?#&oK z`C)qaWREP~$*vjRjER#cW`s}vk;OatYlb&t@?^)%@X0H(c_%N;^kz(*{4q0pazqaA z<j^c{#`MVxv%)8H<nm5t&Gu%@oE(@PK6ytj@8qr7-i+Ck8FRuXXXNotPR;RV%$>Y3 zCw#I*KJR4FTyMtw$%(n)lTYOHPClCJ%~&{DFfV*^MFH>R(mZd*;>ic|!Y6AK@=jLG z_hu}eT$mp|`9>k{<g5AKjOCLR3&JON6!A`OE%0WnoP4n$e6mF`?_|?LZ^r7$jfLTp zUlj9Bep=|wSUcIUD17pa65h#Ei@X`@CqFC-pX^b}JK43^o3U~7#NzPDKT3Hge=YWA zY@X~`5<YoF8Smt!CEkp!lRuV(PmU<(og7-~&DcJ9VQKhejtbt%tYzMeos$F0!YA*j z;GMj+%$u=$GGlr8<cvz*$*JYujJ=aLmWMO;P3Ei!XY8MxSP{-RVe-z3aK?#~1uMfD zCr!?*3}>7?`Cw%@<CMvgRpE?NCl^+QGfta)vMQW$`eeoGaK;&vE33m9XHLFY9nLsw zvSv*<<Lt?eHQ|hNCf}?HXPi6Pur{1=-sH~OaK`zQAJ&F5E|_dt7tXkF^2EAu#zm7~ z)`c@Jp6pm3&bVaq%=&P~rISC_hchml?AZ{`xP0=$hH%CelYcgZGp?K**ci^ZYVyj) zaK_b>8Jofx*G!IV3TIq9d1F&J<GRV5&EbseCnq+CGj5o?vpJk`<7B~>aK=rOGh4zL zH%~s;63)0~vSe#G<JQTAt>KK@CZB8#XWTwnu`Qf&$K=YkaK@dJFSdm<?wYLG9?rOX za$|cq<DSVk+rt_6PB!caXWTcrvm=~w|Kx`q;fx0+TXu#s9-KU}GaNLD)fvusc(P+x zIOCDYGrPhWk52yB70!5UvS)WV<MGW4yX_e#_1H{)z{A1|o;hY<U`Wc$)61P4I8A%< zgB~8HRcxEz^|&#!N`t1-Cx7gz2CKa)0+|!NFT%heu=!(;JQG+LHvc?LhJk@^^T(cW z#>oq2u}lt_;=+`ny!l;E9wS&8bQZSAU4wx^VDiTvaggX_gJ~R0$22BeP20qDRD1Kg zY4;dG^tl;1>YD{7t1)sF9D`H@7RM*M9B`;-VEFeR0zkr`u?A3|fD6Q7U|@jpL0v1* z2pLFtHMIK;8l!Lp2{14)fW{&~`amNupl&)ycr8>NsH^`BB*4JHunsB)8fMrD5({Kt zU|0_oWM^Oi_vt}~Y+wM-27?DQ4noHXKn@340vcsG1JcaEz;GO@Hv`0AU|{GtHQDZ< z+T?_TKDNRP;Q3$%P>TZ8VFnE&ykcNrc+CKwd0=p601v8z<`)^<8NlPTpdo6|L<58O zWWhuFK@kiL43P{B3{eaW44`EvF$@e0u?!3haSRL$@eB+M2@DJjiJ+)vU|>jQ01sj_ z*fW5q6TtmUP$yTFk%0j;=GDf)z|hVxx$lr(J*e&zXJlZIU}RvBWMp8FVq{>DW@KQH zVPs&CWn^HGV`N~EXJlYdU}RuWWMp6f1?XD_1_sao(R>C5h6M}^42z&6SyLGp7$z_< zFid1%V3@?fzyKOH>t<kJ0FAqW#^joyV|R573=9<v3=GAfakvr&NVgI+h6!3z1L~5d zF)%QI)^ub+$3Q`YGfx>97(g)xiYZWRf?^M}%m*~63hKCn#_T}jcpn%T7(jzEprNj% z&>=9;Fxm_T1_sdZ8fYvIG+qZ9!>a_1!Bj!Jp`gLg0tN<#eGCi?`=PN38mR@1<a}aa zU;qt~fyUuLgM6ToOHfx8G)i@vfq?;(0?sioFq~&#U?^u`U;vFWU4f2LU1MNi0F6$8 zMy5ccQl`+PJQtM0Kx1T}Bz1JM=@D(#zYGiv|0c&C(iQ>@i(O)1VAuh&fq{V`;yfrR zse&T?Fara_A!z6dK?f^A9&d-NL1GY?y!FWHdR_+bbUAoz3zSYl2_HoBLDMLx6$TOm zB?nNjgMuGqS|$Sn18CI@C<;Ky3uGfGxq*^hFavm^4K&>inz9B>d4iJ|XdD|94VDbx z=`zrqa6M?&6g1n-pvAzzpvl0%paB|CVE`{m0xd6LP-Xxx;{cCy%Q1kLc7T>#fY$VY zmSBMgT%;Hn7-Se27^E2(KucFZ%TPeeJ3#Ahz<iLrJOcxRA_I7d2!k5bd>v4{YBMl^ zR%0;eF)%RbGcbTh=|Lm%piz2b=%_p>eyth6GX|i!b<kuzXzCe^9T^zFSrJsMz_O<s z0|SFM19<iboHczI7#MsRz;g_s=|2Wg3F6Pdzz_f$TMJ_V&r5-(F2OlB92AexAar10 zU;qUdXe1vLGN7Cb%Eh3N0Oe><ZU*JzBxnu*<pz)*kUS_?fT9Yd50sNZiB^^YlCwck z2g+{splk#h{{|@p#V<%RD22nsK~n`FIgmJL@CB3&RiPvLAOm4)L6(8opphNWs6HsD zLHQUo<_^lkAV+{wJSaDSiYHJSsR!k2kYFVP0|O|lfU+29a33^q56b)?i$Dbe$Y79z zK#l-e3QCMHhk@iki4o)pm>9^xpju!h0|Nu7U;$-CP(B9bXHbCy8gB;`J`+HxWCgU8 z0_9s!K>#Wc7Ed-j;VcWX4rB}{;~jwJc2KSd4O;J+Jn@9P5~zAP0xbhTL)f6w9z=J5 zGB^VR!;H6^g-(hv8iLjs!d93tF~%9_nd%upre#2@2VrYez%qswdd3Vjla)^yOM{#V zT6HMKk&@N6?k7JJW1OL(o`Iej!<@;5rz9DdPwqbD%eZOs%~R<j@Rf>c3u`*(1@01H z6k(bia{3x$%w+8|lG3nMGSzR=&vppCRuW+Z<u_1$ls7s4jHGEL6Sx>?kP=lDY*Y?D zBf@BBYiI$IZ)E~^6dOu2*IjmZb^C<SIcf6RGm_E^m>|ovK7Q3%)yA^$CrGC`NF&3# z$q&y+GVY!H`;4UYStiKpo#+i55viFiIU<a4hI%G?h71h%C+nY;H2cg1o>psUh>z)K zUwlCoWD01yjDdlJ86qR#8$bPH&^&8|{j$uH>&{9@8!>|mhz8bluk8EW+7CfmLHU+} z!E5ryvyzNSlTV+OWUQY2^lZ8TY<(td6%Z3+oVlJMC@w(B4z!}P5V}qX92X{&7n~B| z6kxQoHPJKHGn;I9PMF<T4;*rn#m|{a!j^f$785Zs#+m3D>KQRiHasV0ZDgQl!~knq z!PXfuF~%7|Vjs5Fv^-aJzvf!65CM3UM6ylxJ0~FnTWFVd(|%K^uEkR(MsqzwaF}(m zO>R18Bm-NaSG*^5^*Sd0k6`PKK)&H*pM2q*gbZwH-#tZ1Aud}!Ca|Xr&GZZy%-AQh zoHsIqEh@A!^bV0~yuSvN!t@M4(E?j`_~n+e=)#qc?ZH}&L1tI5PtG~-!_>h(dDnR( zrpfG+-<_9`Sq@!wIeVtcKHtg9zc4YzSwIZh%syG^LYfS0S*PTQiJW&^H>_r2j5F3V z)H7yaxXM0x$ps^(r|gq&Trgt#z&@Ghq7l<?_Q?(xC73ulCP!T~V$$Q7+;>re$%<og z%nb<{*cw++fsMPX`txRh9c=<~S`f$NI~OHnV2f#Gl^!Y|;8fbl#29A=aZDP=WPwW( zGO$&)QH*nLyM3Quz{D753Q>^7Ir+gQiODgSq-0=AYY*@}U+KO%1r)l5dPaJt3=FlL zlP6s=l7X$wt=Re1oYl$`<Rv3;?qq<NA_H5jYcWlCisE6RlT3_t26|wJLKHBSb5GX0 zEWvb^dveYl2^rWL-IKjFeBw-3E0`D!AdX^~$UC{_vJul>zR4RdOE8__n|$iBj|^;O zt^RVm1J7EMYQZrCPRo7*lZ~$UFdY$?+;ByL>8s%6Syzmh3WO$~yCT7~nSJt$D_UHP z!r&?ChUvnSWv+tN1i&aCreh+L=Uw$-nkhQ@%~c5**!osK{X>f+PaPHkr!ufTv0{@I zt{KU|7QQAGs@OVk^IL$EI5-iNh)>SDCSi6Ax}+B^?hP3jV2fj0?5{|BT{z(m)oQ@N zz$`I&&ov*WJjuyi*L}=ji($J{rfl4E>*ReVMo>tDT1c>Ev+eAf^L!U?S`JPOhI*C^ z4Bb+bd#=x7(v+F3al;6jc9=|MCYRkXGJ~y!U9A|g=vV816|gP?P!fuVu9kiCBk69u zFoy})w_usKvXk%KkYL&%H~9y|Je`~1;B>pG#j#2r-1umi{NaMAqA@7{z*e0ei8T1m z)w8W1Yy&v%ixeiWyNNFqL$W^;C;Q|-Hzj21pvze&Za;iDQ^~LcQ3}jfm~3!Mf@zn+ zWUpIBOoeQd>uwn_DJf3Aa9e^2A}0e|6PqXZdH>ZLDwYV%R*I8u&jN+YoZAvi5GSGO zg{}L2zOHg&_@lz_;2diL%CQhT%wX$#=c_j8Xt$;&LCQ%``2$;Z9=ZP=>zsRUHK5UI z$iM(e>P+{PC%4@(VtT1OdDopZ8O+#?14XY9149M-WShGZpt2$Ct`XBDmC0RqjhJqz zOx|}_!VI=f*!J^*ji&@mGoWR;Ap-+!<uFTxQOH@gRYwuo`?>05o_j`23)Ch%+>=1{ z@8q6)Qm}x4#sDacU?FOTwXg+8DE>e;nmpmYi41K0ZKkZ3+2$L+oxp(!ZUhu-PJVD- z!VI?Z*l*t^`?C6fnqURSdPWQkur<n}e4bIs8P~1ADbgI2R?V~~>pd`%fh|^^CeYw$ z9J|gHTo9P*85uH|X-}?sARz-=#r)*WE~x_we=mX+fNB8-4xPyx9!QwMRtrC$R`O|~ z{kPpLj0Sp!7J5bo46yaY2cJ${AuR6x9U)_<Gx^^G2{YINWCN#J@!Q$>nGgzK3w#%? ztjl`Gp?V1+Q>HW7=b?lQY)vzVpq=&(#wlkI3g+lcZg?nR23rIz@#~ji&?&Q2gaX(y z=|c?f+|^z(IUr<i=uAHMP{Ithu3Ae-!<e!A@j`?GP+K3gA0SEW4=2C8$Tx(Hi0)*W zM-noywc01XHOSX237w2kV52)Z;E{wGY;kvx-34tKS;6H91+eAcyy7k|=dCL{j*zL< zojmW6gbZxGcuvBi|JNq&bVMjvsXO`7BNr||6Ub`jev`=xk0s1t%eOOk+N>~P%Y6n` zZ>eW!#DF!*z%n{Ilk*-+n88+roB5pCws6vxDuh<7Q3lqUtTTDfV+k49BJ&QGH5u`O zRuu@XojQ|0JeDwntx7+^9x&bQMeZSl0<2L6Hv5RqWV<I4X0V0sx0}=445!^Xh|r2P z%D`F~bSL*bk&uBdo^P0J{YE*fcUA{NtA_6615YH(V5{xtNgM3C{4zNTp#W=?fz3|W zoy_-C!VI>6f3;g?Y>~bC9E4V^Q3lq!Qg?F9QweF%MiOoYhK7K;oIQ6oZU(iX%pvu5 z>g4{Xl4im-kSJYzdPe2^tV@|pjCB@zrh0}346r5Z6ZNBd)wbGNGBMT}8R!`r=~*P& zOuqM2LIqO+xb4Zn!0-YzwgT#cznd)etSoAQ5~TUwVqtoQv4Za(Y?1tN=9E?Pd%|UO ztii)d4NTgt@za*`ym7E*0B;lGzd57*_q5Y{{jDL*0fskMo}M~yYcK;eGQz;XP^CTj z)w6c#;_}4w^wc8V(o6?Xt5v@$KSejcAT=+sAair}^Uus47{dCx$cl8q#fgbtNqUt- zVsS}oVsU;>X-Q^&UNKlzNj}W9=^xn`WhRTiR-Nw1%BbvwS1r^Egl1iHJ!3rskR?#J z8S9ozU#Q3^Ba7e{>+9+x@pMh}OeQ;gQRD|T)Ae=rL6okMp850u9!4bvuwM~=*VolY RaC8myOhGy~$Gr|T2LS7klBECu delta 12707 zcmbPqgJu0umI->AdrDqB^POP0Q2oy|)vwQWj=g2xw(I<{43-BPFJ^pPKL3fl5+ef$ z9GVy|&t!FAVueEeL<R;10S1PKg8br=^rF<_jQqTOkdihA1_o{hhK6b=oyWkyz{|kU zkdj}Lnpeia5Y52AAk4tf;KjheAjrVbkXoFRnODNV(9Oocz{SAO&<Le@*&+OLD1Qw* z#J-%=GLVt=42z%&`l0kpb_NDckVUDf1-hBV3>j<;4EziX4e@Lc@j09jKFAi3MV~ks z82A_%8iLsv7<d>M8uZv07*rV;8Wh+d;+e&|={fmH4BNON4iRO8cq}tLFTW_Yo`Hc2 zDv*|$m!ex*!0?s_qTmsfF3`=%PfjdJEzr%$%*`xec*F~l|HTUNNiiS9;Ox}OGEm69 z<b%kk<s_Drq^2;uW`#I7wYan-GpCp#wYab}wWyLoN`QfZs~#M51x2Z;3=B6|AwfD- z0OHfc<oqH~7@c8-_-v0LM0^J;1A_=Sgpx|r85kIHi$T^hFsx;TSX`cwnViAEz>ry- zT9L}Y!0=iK;(&d^kSHujEXmN#POVJNNX${oW?*1w5`hF&Mq;sUT25kmxd_A{FHwkw znWB?lG0D|yh(YY-6JubIVqj>P3k`s@#Nv`d1_p+r)Y9V2v`U7_;t+qNNI=}ZK>}ib zhy*0SI-%~*W@TWIV_<0DVSof+G}OE(DTw~8V%^Hb+#H6)qV$5qqT>2gKPiZTEz%IW zTpHp&AsI-(fZ{nZr<lPVYQa?*1_n`3l3-<EkYr$J5P(_;3+VMM3=9ek3=Pv*AoB6@ z3=Ap^3=Ie57#QRk7#iH=85krO7#gO_f$S4uXxOa)aVa7#PL^U(tLIaK*uPx~BK;T2 zPbx}GPAz6&C{c!p?^1?@Gmi>HJuKy=WEO$b=uxORvl1ly@5@2lw^)vWL6(7`p^gRO zo<2E<{(_>^l9J5S$@^I(>u0DlFo-iSH1KPH+{(}ptpN$_A5if>8Vn3V3=9ovnh>`{ zYeMWuElw)U%t>K5rw!4+Lz{s?jDewH5tQzM(q&LOQ5zDbzS@w)U<sk?8&n~T20<wO zR|}%xC6vAjr4K^sby|>Eo(-itpmZsePS%1rI1ozPLup+o-JuTgAjAXp6#IZO52P|M zG?40pEk+O@DlkBzQw*99T$mtyM=MAawOK);)WT}=F1EPE9_(z43nzQ>+B065+{tUt z$U6BXuRWvhWKKSN#@5N6eD;i6CwKDMGyP$le2UMGv3N2kzdhr&$)5c7Os|<IpW?M+ zGG>|VC1}TahlPQ`gn^-fbF!eIInz|O$)^PEI4`m>FxW6KG_Xy+C~CpM4&ks)78EjP z3TB_&C1l6Bhn<1JgMp!eX|f={ITH)VWG-PlP7@A@N`}c31<aWWI3{-q+cB--n0!ju zj_Dc4WG)dqP8m)H1~&$V21c-wB+kiQB6duxIVYbIvE$_8f@ud?<i<7GOVp03i)(V1 zs2%4iE(V4ous)ES4fkX&F+0u%ZUzQ328ITf$%10$Ob56pcZu1t{^4d|u$#;)V$Ed5 zGnq@=jx&#kfx!;!nLtr<rZqg1yTt7{e?SFUCQlSM=QQJmDVZp4&RW9Dz+f@CSKOLu z4e#VG2|LcWP-%wA6D7<!wfP`k=KyQ1<%2ky1spm%`6hQs+Hrp2gP6w*667@Ehd7gY zvY@y*QwINJFDX0Dbx=VjklQ(*KzWRySm0C<fSAcTd7`ofhX4bEDFZ_T7ufQ70t^g( zU@uP;H)nbyF!_|U9h0ZvWG)#y&Kf}m1_uU)1`e>TM+F%etiUP*1<X1B3o<YSfO#N& z{z8+vWbHT`g%}ugz>zpn#GG@j5X8~!U>Au9GcXu|<pM>`Io;qqP;gZULn4t090I3> z85o=x7#f(tJYEq71`7yJ%$(Cz1Y!!yWRMLLL>L%c7#JGZCtnma=ez<{35fz8QHbp< zlR?f67loL~1op~eQAl_&P8Jj~XSy#sxl6&0(?$%Ea9Jh`3Y&8lh(WAn0);W_3NZ$T zfXTeV)|@}Y7#L!}-k2z1&J-d(`IMp^(=zeNTuOFKH^nD=DcLdcOHA%kvg0g}fP@|+ z$Z<^jB_?wz+cB|9PWDo^<8+Z^U~pt$XkY+4u2qtOArzJtId4fq+yTl!7A#T>3=Wff zC9FAfr63W-Jb9v+Ip;|!ND^QHN8*1exMPLPInAXZ7Bhnlp8(}SLgj)qBpet);lL^_ z!@yt#Ha%2^fx(=Cp@9z+=1e^@le^UHIA6&yFnEFe3JN9@*~wh$cC59s3=Bb&dj+gH zU&+E;Bq(6cY9YtK5H{IY(3<tX90P*~nAI%Lzz_#!J(Oo)2m!N96&M)YKrGH`1&BKt zLGEO_s4&?}(~gr@5t7O{CkHB-bGj?S5{96VIp-`zNXW2Ho+xV0c}@|Mj=8}>Ag%;S z7?4EcsRU8U2#(8IC5V~KlP^k}GaXc#?4@nT$)*eugha4|G6RFjWL`0A&N^jC+F%EV z^9f~03Imr_oT4faJ?x-R;`CR6q%c-+TI^MU!~rCWo`b4{ggS>RL?si*sjP0Qu#lRg z3QAU>Fngm43l$?Zh#lYpjk87#W-7?(Thu0V>DzIBRbyZX0T;2LH0Y^5xl7-UX}$X7 zQ~GvH(i)Sw4D2|wH6UdQBiN;zH5eE?!FdQ|3ZLfWQwDZS1)7t&4DC4AXhPh^2=WEf zSIx;?hIXt^wHX-vC-)j!vzq8IF!+L5jd0dEI7?a=CYzzlz~Bv5w^^5g!4u5-182GF zfy8)?Z5Z_?dl}m^>P_x4wrA9zd<sl*nSj_{CiX1)3=HmItxg6oRwtZw0nQRPWMFWe z%xh%B0%m~Rxe(5J24it*8$kkr8B_=|)fi3gGPh$rW(4+{xizb(G1&3u)~rcz)_OSW z51i#`0`{7@HR}`;kT-hGty%BFS!$*rF<wg>M$^e&miCOMle;YK8O<i20+U=;Ahws4 zJ&PIGL*~}3%H}Xu7M!&a&iY{v_L_waiv@@Qva1QsIu2*?SVCnv`z#^p1yahMu!Lj^ z#>o?v%$fdLPUf<+WAd?@>}6-iG|6gmmz^EcWvj`j?5ygAAzdwSBOk;DG4Rn$4B#dj zsEy8`&%nR{>hl?ZG%+wRfM}4s5d#AQ3j?@hVo+jWV2FUqgJ_WYNGLy&fuWv(je&t7 z9x4E$K?Wp34NiiJ<D)?aCNnTFfb@YnBp@xs&>($j4D}%83=C-y3WWwK0QG=C24_O$ zK{QA_3+g~n2M5H@fy#qu5I+~{AW&}?#4mu#W6(B85+H@3t`0~DL^CrmFqD8eP#Pp( z3gv@nrpdVu@?Z~CGB7ZJRM$YARSQ)GqCvXqpnPN+<gEs%`bMZchz6-|f{Hgo#X&SE zLffI@9Z>NOPy~Y5NCM!9=z=Qj21zn7Fo0-~g}qSmKBzb`G$#WC!*r;65DjwR3@CpF zC;~wS&w>hoXpn;0P(CsZ3ZZ#Waby~#e*sh+L~}DRFsx=^0H@523=9k$3=9lAp%J<p zst!bh?AZeje+CAIJy4(Rh0^<=3PCg|i64RTk!e;228NSRgHJ={K{UwVGf;ERLg{l* zc@PbfKMxh3yunGN9^`{d3=9k)1Fu8rJ5UYSXpjMSp=ss;)B%s620n)B1JNLJpF-uI zL&cG4P^aQAEDijHDxg0NjRR6F2Knqi1GrbpAO;E!1_tu!dP)tTKtD)py*MMJAeLZ+ zl!H=GzBEXdfq?-;Lz$p)H82Ln7QTWWCJzcJQ3mj!46Xvd9@L^Iw!{Z#D^NiXvH(Pb zETF8wuV-K&zQhMvOXUI|G#*BDi4U=#0aO!!q6AdXgM>gdsDK(R@IeE#qXj+#sGtWW z3=j=UD5C{FqI@6e1->G|0)KO*_Y>yHxq;r3SNQWzJ{suF$U9juD13560Pp0|Aa6$g z$p?eNCvybyPF4-}W)z%U7#u!%M<DOytHIuk!jlz4!Y5}0@lI|H@n#gAd@&?^vP3ZN zWYbV@M)Apwq2ZHH1oKXQ8tTm`IoU8Qd~!ty@8qdr-i*?dABKfb)(GXD>>BRPC_8y# zc=+TSp}dp7hI=#0Pj-w5pWG3~J9%k@H>2X@j}hUMEy8&xhemocDo<V*89w<%IPYZE zC~rp9$$?SflV?QmPTm^j&8R+^F*<y*M<nm$)M#%;&B+_1!zcfU<ee-U<ISi&IWZ=D z@`@<l$wy<n8FeQM#)eOhh~}MK8tcudKlxy6_+*Y4-pQ(Q-i(Hm3**8k?}*`@d^OIS z(Ri|AeE8&ySl-F4@!pK4lP|`HPnL+|oot%m&1gQkF(G{Ni8$WLPZPWuEhif$hEJ}D z=bbz?(VNkF^25aN$r=f~lU<X%8Eq#|ObVZTBY}7F*CcO7`^k>U;gdTOc_%MT_GWaP z{4qIvvPBZ_<j@pvM(4>3Q^F^|NaCH$n(EEyIyo>keDaKB-pN~2y&2snGp2=4_DJEK zoSNp%=s9^~TKME2DZG<K)4dtJCnu(dPhOGAJNan3H>2-l!Hn?95ox@WOEbI~{U;yH z2%pT6&O2E()0;7Ha$#op<Q?g}ldooaGX_sq%nF~Jk-<B;HOreZbn?Zl@W~RHypv6{ zy&1zNH)e-VK9R{g`DwN{W8`GRobbsNS-g{{=6EwkPkxvaK3OB1cd~1)H)HJNiMipE zZ)EdM{+jE}7(dxDFMM)G4)5fpdEShPlRxH#PqxVAogA9)&6qrSVSf1J7rDHXSqr=w zQzr)&gioH4$2)mzfj49NWX8hq$sYN<lT!=588atuEDWFgBcFG&XpuK#_T<E(@X0F* zcqbn%@@CAPELa>qIiiqva%r(QWB%lW#o?1Vig+ihmUuH3PA)77pS+`pck<N|Z^q)u zilyO`Gm3d9x0ZS{mQKD{8a`Q~gm<!OnKxtk<i@h_$tOy9CqFIoW~`iSSROvPqLg>? z)N*ge>d6nw!zXK$@lJNF@Mf%?Jh38t@{Kay$zLnH8S5uIR)$aRDCeELw9=cgaq`E? z@W~bxypuz#ycwG(FRTim{Gx()GHbOrW9#I=>hQ@kDtRYwt@dVYpUhYjKG~y+cXDct zH)H4IjWywue^l{K7OnMW?4F!h8$NkOHSgr3wcd=qlLhO-8T%$@)`c_nPd-=|&NyMR zWPLc}#L0#A;f#|epR5mOoIF{vA)Il_<jRI{#;KDpHiR=yo2=Ow&NzK?V`DhujLA0} z!x?8zHf#!KoHe<#DV%Zk<cCe+jB_SiHit9LojkEQoN?adm(Agf^CvsDgflLfJhLU7 zapB~TE#ZudCVRGqGcKOIur-`<$>g7{;fzZs2eySXE}OivEu3-rWXASz#ubwz+rt@G zPTtra&bVqaXGb{W>dA>6;f!l0@9YR?Tsv8?Gn{eV<jl@+#`TjAc7`)<m@L^9&bV=M zVOKcgrpYI}!WlPDR_qRE+%mbcJDhRr<cr<mjN2w__JlKTpWN6J&bVXp&7N?^os$iF z!x?u??(7X`+&%eWZ#d(g$(DWLjC&_f><eeyH~D2>IOG1wj{V_`2PV(#4`)2M`D4F5 z<75Y3mdR@-axk4|*&H`Bk8!iYf-{VhKTP3aauA&SZ%PyIFCoa(6N@kdgTUs*nc0k! zFU;No*0y0f2kUMr1_r*(i8I3)CyUJVVCq%e95=Iyku^t+fk9w0<5Y2wLM{_fCxC&W z;kDXirrDcVUx8+^U`C~YR7_qon*&XFbH@Bxs$2~RKvgvZgUP|kM#miL|NVymkl<2i zzsd~6VPIf@@j=aAOQ_f~s2WfM5Y!(72``6=f%@IIKmrU53@e~wpnl$3sMt!V7^ss8 z>a#I3FjzCJg7}1ioq>U2D|9pl<U~+I0@R%au|fI|LNzCV7z_*y8Am2N9ao#2bKJuh zRK<XLMxcJ;Jq8Ab`_KU$a|ZBGBm>Cp)(qf5QU+TF@ZceXJp*_=8#HXs;LHFXGG%aO z01av0Juc4ZGx_6jeOb`pkTC-TXmW@F)L)TgWMBY|UsN$LFjP+tJ*CaY$;iOK#W=a> zgkC);Fdi~6Fo3%8lNlHorZ6xtOk-eR0F5_vGB7Z-FfcH*GB7ZJ78HO6H$V-83I+xS z(C`Roz8uu5E@EI{0FBFl#&SR{bx>CU)bB`OU|;|ZEJZOu797MuN2)*_=$i}-47WfX zTTm!3WME)e#K6D+iX~9b3N)$$8fkgLz`y|NHG>8tW<m!kKm#2;3=9mQ0T9q=31~zG zG|B?%9)PCXK?6vj(W(>%28K-x3=EqY7#Kif37}r~GX@3*(D(&tkOVXWlMfo)0F5+( z#t`;1Fff2(?GOV4!(j#n2GGb8s7ZJNI)-qHfq?-ub^sbT0F4=d1~@>=FF;8Glmb8l z7@)5E3kC*;mkbOHuRwG63=9l!7#JAdGB7Z_V_;x-&%nU&fq{YHBLf4&Ck6(F&yzJz zsSANdHjXhcFwB4sU2vQPr4iXM1_lPuU<XJV6b+z>cF;Hx$mNZb@19y+4~h)Xz#1sP zL9!r!g902B@Zk&$3?LIi8Ng%M489EDF<NlSv0(rYWr9-}D7AsIB`C!hLWdYZ!;V@E z;MsHrWd;WD5Thakcvc-W<qw+82F*s-GsrN2r?f#+*Pvx6pp_h;WhS5%AD}f3ps8rk z6h62+ECg9<0u~2#i$xf~)AkI~(5^3N9#x)!fkBM{yaI$loq>TtgMooTlYxOjn}LBr zj{!XA#h}Z;0PYQ&fg;Zon$AIa-vTNDO8=mI<H*1O&M&aM<G{cG&MUBd<Ho?i;LgAR z?sNMvFfe#CfCukEGclkUH_&VygFgcULofpaLm&eKLl86str!>>K%o^63VzV&D`+td zXv9?ln!Z8lJ(dAHeZ>Gu^Ps*rNE1jNlq^9}1=0sfwxHA}&H%~?kh}uQW1u_)$^syD zpy&nZ1tn{kI4GZi<my2ZpaD=&x(5XvC=-GVgeeAD24aJfGAMt5f*O>sKqUbv(}ElU z%D|wmGRT*pGy*CqKw_X(DWFUa>MnyadN~6F11RHz>;bJR$^<1Zkc&W$09gtO4VcS7 zmVy!^$QLj%kc*cvFfc5JmMEYS22`qmGBGGagGw7v=I)w2^PIEnBnAcsQ0|(*z`)SY zz`y_+#{^|tkZnsQ|2*f;3MzqDPHsFWtOQEVpd1V;Vqv)$L|cG{{y+<)o^4J#FTyx^ z)dd5_yvesONJ@h|09qc^uePwJb6(&sCdN1eJ!3;XBZjug{1<&0Cr*yNm@a~@N`Ub* z<K!C`uQ6IrUVll_6gJUc{U-fvhtO*!5k^p+0TuebOpvL6J^r`t*Pc9?F2ZPMYiO)z zq-PK@`R^r3=@cf&%9qm2b(h^;-99077EU(2EXi0u+557jbT1QR;mzJNTirNjx<w;Y z&6!+(S<-Y36J!BG^ahTI)XbI~5ym(}Jrg}c28Ml1ki{FWt{y!#A}kpo`wjFA^$Zy< zO+I^B()2kKc#5Gxz&C#S$Dn!E2$TOnWfuL&GhjI(m5Y!OoGg7sQd*N4oZ%Zh`57h! zsBJ8SnhdIyCi`EJWQ>}ec_m#2w$g>&ue!WI^PLkDqq&|T*k#jLCV#jp!L*)bGS@XD zCIQyTcGo1#^q>oT9(LR=+30tQgNZTDM9&Q55!h0ody0}mT(*2n;CM1L(=%X*W}Vz~ z&4?+Rb@G905;CwgNndU$i!NOG*dDCTSkHigVJ_?BFV}pS*0N4^x^5%`TYJ^Fa8u~t z+Vi1cn+!ne&ah6Na9x7w2J7U4I}(!*UH4;p%{p1&o+zs^1H&)Y$vQWTn7G&`C)_Y% z5@nk_<%W?AY=N3c_pL{vXO1pqVvIA^Gte_;V9;Zm{OE>}3~WVP-cQRPzF9%iV7tup zj2IZ=*(Mv@lwitWn;h^^LI$?9PNB?eLy?Hr0kGRGK?XIlO|H8sVFp{17kcxdwvfDc z6<C20$kDLXc~OjWZo7S-U%<o|XR2qQXUM?N&p!FgO(Uk6?2~RuFfC%AEOpC>X$|{i zzgrSaU?~Y1*up)FX}VJs4-1`SVyrXJGXa?jRRCM57rFl(>zsRUHJCuj%TUjpf#DP9 z<O{bXWME79PWIODi8EcTU}7|YSkADGdos&yBN^Bdys*I2eu)BGjx#aFndyN;`z_Dp zpxZu7k9a39xGlj{%r|-0Z66uf%DY@mxujK7lKhz%K>-S?lcWSDE8Q`Yfvv2YF~#A? zl^qchVDB1(LKGZrS}JOS;8D~D*iyU1LyAY;XGnep2R%4BNC`~dcSnK=LQVc~$Asy% z&}6l{J~FV?bzCpQW$hRA{DMZO0Ruz1$mG7e5=>1ZlULj|V)7E5eCMu&%uG>8WB6jk zstcZ9=09a(tTWUz)H7jV04Ey>8Q3bj7W*sGUKdWdGcm>)LHw>EHreH#57T7v$&>E+ zFoj4=esE7h2DaF)on3RD@8V6%p@D75z_3ALvdH~eOny?6H{3U3iiaefD5=T+?i<O# zR?w|hj9B!m^}h;O7dU`hq$m44kdT2bt$WR*Aj#dNYJ~9BRhh{R4~%4BOX1|19>oQ| zdk0EEpg=bTEoYp3?tvE5dD+Ro9w;#N$xW7dD8V#cZnD8MSjsiSoz1c4XhV?87RybZ z_fUfAfZXIiPbHY{%T3OEBr*BbLn)?dER)$D8OgXq7wt{F?a8?5VnREj=s?lJ6fZxy z<IyZ^?zhx40L25usf5kD!8*C;u>>A<yA>uMcq}1<B|Cs3)DV^(n3$C&^F1+Q;!~RJ z^d!v;wpy|~Wy;1qw@%)N#=jA$M1rh*+pjbGmUXCv7dX<4K>3}EZSuV*Moin4CJQ|^ zl7THl3{80R|JQ`XZ(tLQL7BTmd2+&22^rXWM3xAnkh5&7j)JoTIQR3YOrG-8$PBh1 zaowHWZxoAlq`=t#6bTFjLfHr!(Rd1SaQGXU;WkJBx>~b%Pw47(O#C0gmV?U|NTfqz z&}g#6a}%Zx^~rwECCp%pAo-S`SsFO~ZW7qXrh29f46tR8e)~4rm(~B%1gB$g&ga*d zJm<LtQ?$n9ZO@I&V9O+@2{bqw$F6e)7nP=ZMurTq1(PlRx6b=5A({scb#PduX-<}V zAz=nvn3%cKW`zk`?lTrf13g0vJtG4K*wV%4(@H)qwEwmnArq)IIp>9h3~a5Vna`PR z3ny)<LMSNJn!MnJgc)pU;i8pwS?@ShFCi4bmrt^+$%q%UszAuB)0+J5g@hSwz2yn^ zfaz{8at|RCz*b~R{Q6}WbjmChA@fpevdv2g8Q2oe+s$cihSP2xL?{r{o?P%!!VI?N zGfC_ZC%?SNH-rM{ve1Uf)^C)vdS`VYWPG(J?|Ug>23touPugJD<(J7(2nDc}ra^WW zv}I%kmm_3)v?uetl8}KdO<nDl8CztpJ_n&-hxTNLR}xI;v?oWsa<MBmf~=#2t+Tv$ zZ~xrYMtd#6>MivQjTo>-8Cb?%Yx12}5;CyGrw5--Tp=v({vDw;S!=SuYY8*hYE=WL zS@GN1_?Zw2utpi!?AcnA<6cXc!4|-B2-<1yV4QLWp%rVCfwf-Mn!M(<gbZv=?IDJD z?rJZY91vRnYE6FdTEYyr2v<u;!<e!A@j`?GtWgFw+fsY7-Wv%s*uvfu-x}m=mV{15 zXvG?3V6A1^lWX2c$iUVL^NPE?oVTv*I6~_p?a3S7NSMJE7w04_`hRWWPDg|S*z)6x z3k774XuR}C$gE|Z{O^r~8G2ipi4jy?8k#ULSXe=#dGYBPmGiSMWim0=S?HPS85%G+ zT21zOD<K10Kg*eKbL>^%tldnEb*6eoW_l(d1r2W{xDr6!dIkoD2hS!idRxYHRAI8z zJ2|UBOGq1-NxL<E+H#&Zsg{t|H2=*R?Z2m;-dkb`X)7?ix$^YXd0PVkP~ROiU#&E` X=w16}srPT0r^gF2a&12S#oZhLaGD@< diff --git a/src/db/migrations/0003_tired_stone_men.sql b/src/db/migrations/0000_flawless_scarecrow.sql similarity index 96% rename from src/db/migrations/0003_tired_stone_men.sql rename to src/db/migrations/0000_flawless_scarecrow.sql index a5140ea..b967690 100644 --- a/src/db/migrations/0003_tired_stone_men.sql +++ b/src/db/migrations/0000_flawless_scarecrow.sql @@ -66,6 +66,17 @@ CREATE TABLE IF NOT EXISTS "collections" ( CONSTRAINT "collections_id_unique" UNIQUE("id") ); --> statement-breakpoint +CREATE TABLE IF NOT EXISTS "commentReply" ( + "id" serial PRIMARY KEY NOT NULL, + "user_id" integer NOT NULL, + "comment_id" integer NOT NULL, + "text" text NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL, + "deleted_at" timestamp, + "update_at" timestamp DEFAULT now() NOT NULL, + CONSTRAINT "commentReply_id_unique" UNIQUE("id") +); +--> statement-breakpoint CREATE TABLE IF NOT EXISTS "comments" ( "id" serial PRIMARY KEY NOT NULL, "user_id" integer NOT NULL, @@ -206,6 +217,7 @@ CREATE TABLE IF NOT EXISTS "resource_stats" ( "shares" integer DEFAULT 0 NOT NULL, "score" numeric DEFAULT '0.0' NOT NULL, "follows" integer DEFAULT 0 NOT NULL, + "comments" integer DEFAULT 0 NOT NULL, CONSTRAINT "resource_stats_id_unique" UNIQUE("id") ); --> statement-breakpoint @@ -376,6 +388,18 @@ EXCEPTION WHEN duplicate_object THEN null; END $$; --> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "commentReply" ADD CONSTRAINT "commentReply_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "commentReply" ADD CONSTRAINT "commentReply_comment_id_comments_id_fk" FOREIGN KEY ("comment_id") REFERENCES "public"."comments"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint DO $$ BEGIN ALTER TABLE "comments" ADD CONSTRAINT "comments_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; EXCEPTION diff --git a/src/db/migrations/0000_secret_sharon_ventura.sql b/src/db/migrations/0000_secret_sharon_ventura.sql deleted file mode 100644 index b18047a..0000000 --- a/src/db/migrations/0000_secret_sharon_ventura.sql +++ /dev/null @@ -1,588 +0,0 @@ -DO $$ BEGIN - CREATE TYPE "public"."state" AS ENUM('active', 'inactive', 'under_review'); -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "achievements" ( - "id" serial PRIMARY KEY NOT NULL, - "name" varchar(255) NOT NULL, - "description" text, - "reward_experience" numeric, - "reward_points" numeric, - "state" "state" DEFAULT 'inactive' NOT NULL, - "repeatable" integer NOT NULL, - "is_resettable" boolean NOT NULL, - "created_at" timestamp DEFAULT now() NOT NULL, - "updated_at" timestamp DEFAULT now() NOT NULL, - CONSTRAINT "achievements_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "actions" ( - "id" serial PRIMARY KEY NOT NULL, - "name" varchar(255) NOT NULL, - "created_at" timestamp DEFAULT now() NOT NULL, - "updated_at" timestamp DEFAULT now() NOT NULL, - CONSTRAINT "actions_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "collection_likes" ( - "id" serial PRIMARY KEY NOT NULL, - "user_id" integer NOT NULL, - "collection" integer NOT NULL, - CONSTRAINT "collection_likes_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "collection_resources" ( - "id" serial PRIMARY KEY NOT NULL, - "collection_id" integer NOT NULL, - "resource_id" integer NOT NULL, - CONSTRAINT "collection_resources_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "collection_stats" ( - "id" serial PRIMARY KEY NOT NULL, - "views" integer DEFAULT 0 NOT NULL, - "downloads" integer DEFAULT 0 NOT NULL, - "likes" integer DEFAULT 0 NOT NULL, - "shares" integer DEFAULT 0 NOT NULL, - "score" numeric DEFAULT '0.0' NOT NULL, - "follows" integer DEFAULT 0 NOT NULL, - CONSTRAINT "collection_stats_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "collections" ( - "id" serial PRIMARY KEY NOT NULL, - "name" varchar(255), - "description" text, - "is_private" boolean DEFAULT false, - "is_active" boolean DEFAULT true, - "created_at" timestamp DEFAULT now() NOT NULL, - "updated_at" timestamp DEFAULT now() NOT NULL, - "deleted_at" timestamp, - "thumbnail" varchar(255), - "user_id" integer NOT NULL, - "collection_stats_id" integer NOT NULL, - CONSTRAINT "collections_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "complaints" ( - "id" serial PRIMARY KEY NOT NULL, - "state" "state" DEFAULT 'under_review' NOT NULL, - "description" text NOT NULL, - "denouncer_id" integer NOT NULL, - "resource_id" integer NOT NULL, - "collection_id" integer, - "user_id" integer, - "evaluated_at" timestamp, - "created_at" timestamp DEFAULT now() NOT NULL, - "q1" boolean, - "q2" boolean, - "q3" boolean, - "q4" boolean, - CONSTRAINT "complaints_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "educational_stages" ( - "id" serial PRIMARY KEY NOT NULL, - "name" varchar(255) NOT NULL, - CONSTRAINT "educational_stages_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "followers" ( - "id" serial PRIMARY KEY NOT NULL, - "user_id" integer NOT NULL, - "follower_id" integer NOT NULL, - CONSTRAINT "followers_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "institutions" ( - "id" serial PRIMARY KEY NOT NULL, - "name" varchar(255) NOT NULL, - "uf" varchar(2), - "city" varchar(255), - "cep" varchar(10), - "created_at" timestamp DEFAULT now() NOT NULL, - "updated_at" timestamp DEFAULT now() NOT NULL, - CONSTRAINT "institutions_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "items" ( - "id" serial PRIMARY KEY NOT NULL, - "name" varchar(255) NOT NULL, - "price" numeric, - "discount" numeric, - "description" text, - "is_active" boolean DEFAULT false, - "created_at" timestamp DEFAULT now() NOT NULL, - "updated_at" timestamp DEFAULT now() NOT NULL, - "achievement_id" integer, - CONSTRAINT "items_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "languages" ( - "id" serial PRIMARY KEY NOT NULL, - "name" varchar(255) NOT NULL, - "code" varchar(10) NOT NULL, - CONSTRAINT "languages_id_unique" UNIQUE("id"), - CONSTRAINT "languages_code_unique" UNIQUE("code") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "licenses" ( - "id" serial PRIMARY KEY NOT NULL, - "name" varchar(255) NOT NULL, - "description" text NOT NULL, - "url" varchar(255) NOT NULL, - CONSTRAINT "licenses_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "notifications" ( - "id" serial PRIMARY KEY NOT NULL, - "action_id" integer NOT NULL, - "actor_user_id" integer NOT NULL, - "target_user_id" integer NOT NULL, - "target_resource_id" integer, - "target_collection_id" integer, - "created_at" timestamp DEFAULT now() NOT NULL, - "updated_at" timestamp DEFAULT now() NOT NULL, - CONSTRAINT "notifications_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "object_types" ( - "id" serial PRIMARY KEY NOT NULL, - "name" varchar(255) NOT NULL, - CONSTRAINT "object_types_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "reset_tickets" ( - "id" serial PRIMARY KEY NOT NULL, - "user_id" integer NOT NULL, - "token_hash" varchar(255) NOT NULL, - "expiration_date" timestamp NOT NULL, - "token_used" boolean DEFAULT false NOT NULL, - "valid_token" boolean DEFAULT true NOT NULL, - "created_at" timestamp DEFAULT now() NOT NULL, - "updated_at" timestamp DEFAULT now() NOT NULL, - CONSTRAINT "reset_tickets_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "resource_educational_stages" ( - "id" serial PRIMARY KEY NOT NULL, - "resource_id" integer NOT NULL, - "educational_stage_id" integer NOT NULL, - CONSTRAINT "resource_educational_stages_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "resource_languages" ( - "id" serial PRIMARY KEY NOT NULL, - "resource_id" integer NOT NULL, - "language_id" integer NOT NULL, - CONSTRAINT "resource_languages_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "resource_likes" ( - "id" serial PRIMARY KEY NOT NULL, - "user_id" integer NOT NULL, - "resource_id" integer NOT NULL, - CONSTRAINT "resource_likes_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "resource_stats" ( - "id" serial PRIMARY KEY NOT NULL, - "views" integer DEFAULT 0 NOT NULL, - "downloads" integer DEFAULT 0 NOT NULL, - "likes" integer DEFAULT 0 NOT NULL, - "shares" integer DEFAULT 0 NOT NULL, - "score" numeric DEFAULT '0.0' NOT NULL, - "follows" integer DEFAULT 0 NOT NULL, - CONSTRAINT "resource_stats_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "resource_subjects" ( - "id" serial PRIMARY KEY NOT NULL, - "resource_id" integer NOT NULL, - "subject_id" integer NOT NULL, - CONSTRAINT "resource_subjects_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "resources" ( - "id" serial PRIMARY KEY NOT NULL, - "name" varchar(255) NOT NULL, - "author" varchar(255) NOT NULL, - "bucket_key" varchar(255), - "link" varchar(255), - "thumbnail" varchar(255) NOT NULL, - "description" text, - "active" boolean DEFAULT false NOT NULL, - "created_at" timestamp DEFAULT now() NOT NULL, - "updated_at" timestamp DEFAULT now() NOT NULL, - "published_at" timestamp, - "submitted_at" timestamp, - "deleted_at" timestamp, - "user_id" integer NOT NULL, - "resource_stats_id" integer NOT NULL, - "object_type_id" integer NOT NULL, - "license_id" integer NOT NULL, - CONSTRAINT "resources_id_unique" UNIQUE("id"), - CONSTRAINT "resources_bucket_key_unique" UNIQUE("bucket_key"), - CONSTRAINT "resources_resource_stats_id_unique" UNIQUE("resource_stats_id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "roles" ( - "id" serial PRIMARY KEY NOT NULL, - "name" varchar(255) NOT NULL, - "description" text, - "created_at" timestamp DEFAULT now() NOT NULL, - "updated_at" timestamp DEFAULT now() NOT NULL, - CONSTRAINT "roles_id_unique" UNIQUE("id"), - CONSTRAINT "roles_name_unique" UNIQUE("name") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "subjects" ( - "id" serial PRIMARY KEY NOT NULL, - "name" varchar(255) NOT NULL, - CONSTRAINT "subjects_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "submissions" ( - "id" serial PRIMARY KEY NOT NULL, - "is_accepted" boolean DEFAULT false NOT NULL, - "justification" text, - "resource_id" integer NOT NULL, - "submitter_id" integer NOT NULL, - "curator_id" integer, - "created_at" timestamp DEFAULT now() NOT NULL, - "updated_at" timestamp DEFAULT now() NOT NULL, - "answered_at" timestamp, - "q1" boolean, - "q2" boolean, - "q3" boolean, - "q4" boolean, - CONSTRAINT "submissions_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "user_achievements" ( - "id" serial PRIMARY KEY NOT NULL, - "user_id" integer NOT NULL, - "achievement_id" integer NOT NULL, - CONSTRAINT "user_achievements_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "user_institutions" ( - "id" serial PRIMARY KEY NOT NULL, - "user_id" integer NOT NULL, - "institution_id" integer NOT NULL, - CONSTRAINT "user_institutions_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "user_items" ( - "id" serial PRIMARY KEY NOT NULL, - "user_id" integer NOT NULL, - "item_id" integer NOT NULL, - CONSTRAINT "user_items_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "user_roles" ( - "id" serial PRIMARY KEY NOT NULL, - "user_id" integer NOT NULL, - "role_id" integer NOT NULL, - CONSTRAINT "user_roles_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "user_stats" ( - "id" serial PRIMARY KEY NOT NULL, - "score" numeric DEFAULT '0.0' NOT NULL, - "likes" integer DEFAULT 0 NOT NULL, - "likes_received" integer DEFAULT 0 NOT NULL, - "follows" integer DEFAULT 0 NOT NULL, - "followers" integer DEFAULT 0 NOT NULL, - "collections" integer DEFAULT 0 NOT NULL, - "submitted_resources" integer DEFAULT 0 NOT NULL, - "approved_resources" integer DEFAULT 0 NOT NULL, - "reviewed_resources" integer DEFAULT 0 NOT NULL, - "comments" integer DEFAULT 0 NOT NULL, - CONSTRAINT "user_stats_id_unique" UNIQUE("id") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "users" ( - "id" serial PRIMARY KEY NOT NULL, - "name" varchar(255) NOT NULL, - "username" varchar(255) NOT NULL, - "password" varchar(255) NOT NULL, - "email" varchar(255) NOT NULL, - "description" text DEFAULT 'sem descrição', - "institution" text DEFAULT 'sem instituição', - "birthday" timestamp NOT NULL, - "cpf" varchar(11) NOT NULL, - "created_at" timestamp DEFAULT now() NOT NULL, - "updated_at" timestamp DEFAULT now() NOT NULL, - "confirmed_at" timestamp, - "confirmation_sent_at" timestamp, - "deleted_at" timestamp, - "reactivated_at" timestamp, - "active" boolean DEFAULT true, - "user_stats_id" integer NOT NULL, - CONSTRAINT "users_id_unique" UNIQUE("id"), - CONSTRAINT "users_username_unique" UNIQUE("username"), - CONSTRAINT "users_email_unique" UNIQUE("email"), - CONSTRAINT "users_cpf_unique" UNIQUE("cpf"), - CONSTRAINT "users_user_stats_id_unique" UNIQUE("user_stats_id") -); ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "collection_likes" ADD CONSTRAINT "collection_likes_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "collection_likes" ADD CONSTRAINT "collection_likes_collection_collections_id_fk" FOREIGN KEY ("collection") REFERENCES "public"."collections"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "collection_resources" ADD CONSTRAINT "collection_resources_collection_id_collections_id_fk" FOREIGN KEY ("collection_id") REFERENCES "public"."collections"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "collection_resources" ADD CONSTRAINT "collection_resources_resource_id_resources_id_fk" FOREIGN KEY ("resource_id") REFERENCES "public"."resources"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "collections" ADD CONSTRAINT "collections_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "collections" ADD CONSTRAINT "collections_collection_stats_id_collection_stats_id_fk" FOREIGN KEY ("collection_stats_id") REFERENCES "public"."collection_stats"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "complaints" ADD CONSTRAINT "complaints_denouncer_id_users_id_fk" FOREIGN KEY ("denouncer_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "complaints" ADD CONSTRAINT "complaints_resource_id_resources_id_fk" FOREIGN KEY ("resource_id") REFERENCES "public"."resources"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "complaints" ADD CONSTRAINT "complaints_collection_id_collections_id_fk" FOREIGN KEY ("collection_id") REFERENCES "public"."collections"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "complaints" ADD CONSTRAINT "complaints_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "followers" ADD CONSTRAINT "followers_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "followers" ADD CONSTRAINT "followers_follower_id_users_id_fk" FOREIGN KEY ("follower_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "items" ADD CONSTRAINT "items_achievement_id_achievements_id_fk" FOREIGN KEY ("achievement_id") REFERENCES "public"."achievements"("id") ON DELETE no action ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "notifications" ADD CONSTRAINT "notifications_action_id_actions_id_fk" FOREIGN KEY ("action_id") REFERENCES "public"."actions"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "notifications" ADD CONSTRAINT "notifications_actor_user_id_users_id_fk" FOREIGN KEY ("actor_user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "notifications" ADD CONSTRAINT "notifications_target_user_id_users_id_fk" FOREIGN KEY ("target_user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "notifications" ADD CONSTRAINT "notifications_target_resource_id_resources_id_fk" FOREIGN KEY ("target_resource_id") REFERENCES "public"."resources"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "notifications" ADD CONSTRAINT "notifications_target_collection_id_collections_id_fk" FOREIGN KEY ("target_collection_id") REFERENCES "public"."collections"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "reset_tickets" ADD CONSTRAINT "reset_tickets_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "resource_educational_stages" ADD CONSTRAINT "resource_educational_stages_resource_id_resources_id_fk" FOREIGN KEY ("resource_id") REFERENCES "public"."resources"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "resource_educational_stages" ADD CONSTRAINT "resource_educational_stages_educational_stage_id_educational_stages_id_fk" FOREIGN KEY ("educational_stage_id") REFERENCES "public"."educational_stages"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "resource_languages" ADD CONSTRAINT "resource_languages_resource_id_resources_id_fk" FOREIGN KEY ("resource_id") REFERENCES "public"."resources"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "resource_languages" ADD CONSTRAINT "resource_languages_language_id_languages_id_fk" FOREIGN KEY ("language_id") REFERENCES "public"."languages"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "resource_likes" ADD CONSTRAINT "resource_likes_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "resource_likes" ADD CONSTRAINT "resource_likes_resource_id_resources_id_fk" FOREIGN KEY ("resource_id") REFERENCES "public"."resources"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "resource_subjects" ADD CONSTRAINT "resource_subjects_resource_id_resources_id_fk" FOREIGN KEY ("resource_id") REFERENCES "public"."resources"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "resource_subjects" ADD CONSTRAINT "resource_subjects_subject_id_subjects_id_fk" FOREIGN KEY ("subject_id") REFERENCES "public"."subjects"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "resources" ADD CONSTRAINT "resources_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "resources" ADD CONSTRAINT "resources_resource_stats_id_resource_stats_id_fk" FOREIGN KEY ("resource_stats_id") REFERENCES "public"."resource_stats"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "resources" ADD CONSTRAINT "resources_object_type_id_object_types_id_fk" FOREIGN KEY ("object_type_id") REFERENCES "public"."object_types"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "resources" ADD CONSTRAINT "resources_license_id_licenses_id_fk" FOREIGN KEY ("license_id") REFERENCES "public"."licenses"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "submissions" ADD CONSTRAINT "submissions_resource_id_resources_id_fk" FOREIGN KEY ("resource_id") REFERENCES "public"."resources"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "submissions" ADD CONSTRAINT "submissions_submitter_id_users_id_fk" FOREIGN KEY ("submitter_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "submissions" ADD CONSTRAINT "submissions_curator_id_users_id_fk" FOREIGN KEY ("curator_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "user_achievements" ADD CONSTRAINT "user_achievements_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "user_achievements" ADD CONSTRAINT "user_achievements_achievement_id_users_id_fk" FOREIGN KEY ("achievement_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "user_institutions" ADD CONSTRAINT "user_institutions_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "user_institutions" ADD CONSTRAINT "user_institutions_institution_id_institutions_id_fk" FOREIGN KEY ("institution_id") REFERENCES "public"."institutions"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "user_items" ADD CONSTRAINT "user_items_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "user_items" ADD CONSTRAINT "user_items_item_id_items_id_fk" FOREIGN KEY ("item_id") REFERENCES "public"."items"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_role_id_roles_id_fk" FOREIGN KEY ("role_id") REFERENCES "public"."roles"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "users" ADD CONSTRAINT "users_user_stats_id_user_stats_id_fk" FOREIGN KEY ("user_stats_id") REFERENCES "public"."user_stats"("id") ON DELETE no action ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; diff --git a/src/db/migrations/0001_odd_valkyrie.sql b/src/db/migrations/0001_odd_valkyrie.sql new file mode 100644 index 0000000..884fc4d --- /dev/null +++ b/src/db/migrations/0001_odd_valkyrie.sql @@ -0,0 +1,18 @@ +CREATE TABLE IF NOT EXISTS "userCollections" ( + "id" serial PRIMARY KEY NOT NULL, + "user_id" integer NOT NULL, + "collection_id" integer NOT NULL, + CONSTRAINT "userCollections_id_unique" UNIQUE("id") +); +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "userCollections" ADD CONSTRAINT "userCollections_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "userCollections" ADD CONSTRAINT "userCollections_collection_id_collections_id_fk" FOREIGN KEY ("collection_id") REFERENCES "public"."collections"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; diff --git a/src/db/migrations/0001_strange_famine.sql b/src/db/migrations/0001_strange_famine.sql deleted file mode 100644 index f705a53..0000000 --- a/src/db/migrations/0001_strange_famine.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE "users" DROP CONSTRAINT "users_username_unique"; \ No newline at end of file diff --git a/src/db/migrations/0002_sleepy_vin_gonzales.sql b/src/db/migrations/0002_sleepy_vin_gonzales.sql deleted file mode 100644 index 1292179..0000000 --- a/src/db/migrations/0002_sleepy_vin_gonzales.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE "users" ADD CONSTRAINT "users_username_unique" UNIQUE("username"); \ No newline at end of file diff --git a/src/db/migrations/0004_useful_paper_doll.sql b/src/db/migrations/0004_useful_paper_doll.sql deleted file mode 100644 index 2927b5a..0000000 --- a/src/db/migrations/0004_useful_paper_doll.sql +++ /dev/null @@ -1,22 +0,0 @@ -CREATE TABLE IF NOT EXISTS "commentReply" ( - "id" serial PRIMARY KEY NOT NULL, - "user_id" integer NOT NULL, - "comment_id" integer NOT NULL, - "text" text NOT NULL, - "created_at" timestamp DEFAULT now() NOT NULL, - "deleted_at" timestamp, - "update_at" timestamp DEFAULT now() NOT NULL, - CONSTRAINT "commentReply_id_unique" UNIQUE("id") -); ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "commentReply" ADD CONSTRAINT "commentReply_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "commentReply" ADD CONSTRAINT "commentReply_comment_id_comments_id_fk" FOREIGN KEY ("comment_id") REFERENCES "public"."comments"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; diff --git a/src/db/migrations/0005_eager_darkstar.sql b/src/db/migrations/0005_eager_darkstar.sql deleted file mode 100644 index 96894d5..0000000 --- a/src/db/migrations/0005_eager_darkstar.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE "resource_stats" ADD COLUMN "comments" integer DEFAULT 0 NOT NULL; \ No newline at end of file diff --git a/src/db/migrations/meta/0005_snapshot.json b/src/db/migrations/meta/0000_snapshot.json similarity index 99% rename from src/db/migrations/meta/0005_snapshot.json rename to src/db/migrations/meta/0000_snapshot.json index 6ec69be..d7bd906 100644 --- a/src/db/migrations/meta/0005_snapshot.json +++ b/src/db/migrations/meta/0000_snapshot.json @@ -1,6 +1,6 @@ { - "id": "5b878977-1a6e-45e4-8290-26e30a5be5b5", - "prevId": "e2262718-fe9a-4922-8886-5b981115dce9", + "id": "e5bfc3f7-888b-4164-9ff2-fe7328153ca6", + "prevId": "00000000-0000-0000-0000-000000000000", "version": "7", "dialect": "postgresql", "tables": { diff --git a/src/db/migrations/meta/0004_snapshot.json b/src/db/migrations/meta/0001_snapshot.json similarity index 97% rename from src/db/migrations/meta/0004_snapshot.json rename to src/db/migrations/meta/0001_snapshot.json index f52c13c..a63aea5 100644 --- a/src/db/migrations/meta/0004_snapshot.json +++ b/src/db/migrations/meta/0001_snapshot.json @@ -1,6 +1,6 @@ { - "id": "e2262718-fe9a-4922-8886-5b981115dce9", - "prevId": "9a77c1e8-63d4-4588-9c9f-bb93ff5fa910", + "id": "8bb70cc6-4e1b-4435-baaa-8d1a6917165f", + "prevId": "e5bfc3f7-888b-4164-9ff2-fe7328153ca6", "version": "7", "dialect": "postgresql", "tables": { @@ -1584,6 +1584,13 @@ "primaryKey": false, "notNull": true, "default": 0 + }, + "comments": { + "name": "comments", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 } }, "indexes": {}, @@ -2141,6 +2148,69 @@ } } }, + "public.userCollections": { + "name": "userCollections", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "collection_id": { + "name": "collection_id", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "userCollections_user_id_users_id_fk": { + "name": "userCollections_user_id_users_id_fk", + "tableFrom": "userCollections", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "userCollections_collection_id_collections_id_fk": { + "name": "userCollections_collection_id_collections_id_fk", + "tableFrom": "userCollections", + "tableTo": "collections", + "columnsFrom": [ + "collection_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "userCollections_id_unique": { + "name": "userCollections_id_unique", + "nullsNotDistinct": false, + "columns": [ + "id" + ] + } + } + }, "public.user_institutions": { "name": "user_institutions", "schema": "", diff --git a/src/db/migrations/meta/0003_snapshot.json b/src/db/migrations/meta/0003_snapshot.json deleted file mode 100644 index a71853c..0000000 --- a/src/db/migrations/meta/0003_snapshot.json +++ /dev/null @@ -1,2523 +0,0 @@ -{ - "id": "9a77c1e8-63d4-4588-9c9f-bb93ff5fa910", - "prevId": "00000000-0000-0000-0000-000000000000", - "version": "7", - "dialect": "postgresql", - "tables": { - "public.achievements": { - "name": "achievements", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "reward_experience": { - "name": "reward_experience", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "reward_points": { - "name": "reward_points", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "state": { - "name": "state", - "type": "state", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'inactive'" - }, - "repeatable": { - "name": "repeatable", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "is_resettable": { - "name": "is_resettable", - "type": "boolean", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "achievements_id_unique": { - "name": "achievements_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.actions": { - "name": "actions", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "actions_id_unique": { - "name": "actions_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.collection_likes": { - "name": "collection_likes", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "collection": { - "name": "collection", - "type": "integer", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "collection_likes_user_id_users_id_fk": { - "name": "collection_likes_user_id_users_id_fk", - "tableFrom": "collection_likes", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "collection_likes_collection_collections_id_fk": { - "name": "collection_likes_collection_collections_id_fk", - "tableFrom": "collection_likes", - "tableTo": "collections", - "columnsFrom": [ - "collection" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "collection_likes_id_unique": { - "name": "collection_likes_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.collection_resources": { - "name": "collection_resources", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "collection_id": { - "name": "collection_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "resource_id": { - "name": "resource_id", - "type": "integer", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "collection_resources_collection_id_collections_id_fk": { - "name": "collection_resources_collection_id_collections_id_fk", - "tableFrom": "collection_resources", - "tableTo": "collections", - "columnsFrom": [ - "collection_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "collection_resources_resource_id_resources_id_fk": { - "name": "collection_resources_resource_id_resources_id_fk", - "tableFrom": "collection_resources", - "tableTo": "resources", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "collection_resources_id_unique": { - "name": "collection_resources_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.collection_stats": { - "name": "collection_stats", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "views": { - "name": "views", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "downloads": { - "name": "downloads", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "likes": { - "name": "likes", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "shares": { - "name": "shares", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "score": { - "name": "score", - "type": "numeric", - "primaryKey": false, - "notNull": true, - "default": "'0.0'" - }, - "follows": { - "name": "follows", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "collection_stats_id_unique": { - "name": "collection_stats_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.collections": { - "name": "collections", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "is_private": { - "name": "is_private", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "is_active": { - "name": "is_active", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "deleted_at": { - "name": "deleted_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "thumbnail": { - "name": "thumbnail", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "collection_stats_id": { - "name": "collection_stats_id", - "type": "integer", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "collections_user_id_users_id_fk": { - "name": "collections_user_id_users_id_fk", - "tableFrom": "collections", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "collections_collection_stats_id_collection_stats_id_fk": { - "name": "collections_collection_stats_id_collection_stats_id_fk", - "tableFrom": "collections", - "tableTo": "collection_stats", - "columnsFrom": [ - "collection_stats_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "collections_id_unique": { - "name": "collections_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.comments": { - "name": "comments", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "resource_id": { - "name": "resource_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "text": { - "name": "text", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "deleted_at": { - "name": "deleted_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "update_at": { - "name": "update_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "comments_user_id_users_id_fk": { - "name": "comments_user_id_users_id_fk", - "tableFrom": "comments", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "comments_resource_id_resources_id_fk": { - "name": "comments_resource_id_resources_id_fk", - "tableFrom": "comments", - "tableTo": "resources", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "comments_id_unique": { - "name": "comments_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.complaints": { - "name": "complaints", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "state": { - "name": "state", - "type": "state", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'under_review'" - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "denouncer_id": { - "name": "denouncer_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "resource_id": { - "name": "resource_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "collection_id": { - "name": "collection_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "evaluated_at": { - "name": "evaluated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "q1": { - "name": "q1", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "q2": { - "name": "q2", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "q3": { - "name": "q3", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "q4": { - "name": "q4", - "type": "boolean", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "complaints_denouncer_id_users_id_fk": { - "name": "complaints_denouncer_id_users_id_fk", - "tableFrom": "complaints", - "tableTo": "users", - "columnsFrom": [ - "denouncer_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "complaints_resource_id_resources_id_fk": { - "name": "complaints_resource_id_resources_id_fk", - "tableFrom": "complaints", - "tableTo": "resources", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "complaints_collection_id_collections_id_fk": { - "name": "complaints_collection_id_collections_id_fk", - "tableFrom": "complaints", - "tableTo": "collections", - "columnsFrom": [ - "collection_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "complaints_user_id_users_id_fk": { - "name": "complaints_user_id_users_id_fk", - "tableFrom": "complaints", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "complaints_id_unique": { - "name": "complaints_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.educational_stages": { - "name": "educational_stages", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "educational_stages_id_unique": { - "name": "educational_stages_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.followers": { - "name": "followers", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "follower_id": { - "name": "follower_id", - "type": "integer", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "followers_user_id_users_id_fk": { - "name": "followers_user_id_users_id_fk", - "tableFrom": "followers", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "followers_follower_id_users_id_fk": { - "name": "followers_follower_id_users_id_fk", - "tableFrom": "followers", - "tableTo": "users", - "columnsFrom": [ - "follower_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "followers_id_unique": { - "name": "followers_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.institutions": { - "name": "institutions", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "uf": { - "name": "uf", - "type": "varchar(2)", - "primaryKey": false, - "notNull": false - }, - "city": { - "name": "city", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "cep": { - "name": "cep", - "type": "varchar(10)", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "institutions_id_unique": { - "name": "institutions_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.items": { - "name": "items", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "price": { - "name": "price", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "discount": { - "name": "discount", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "is_active": { - "name": "is_active", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "achievement_id": { - "name": "achievement_id", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "items_achievement_id_achievements_id_fk": { - "name": "items_achievement_id_achievements_id_fk", - "tableFrom": "items", - "tableTo": "achievements", - "columnsFrom": [ - "achievement_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "items_id_unique": { - "name": "items_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.languages": { - "name": "languages", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "code": { - "name": "code", - "type": "varchar(10)", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "languages_id_unique": { - "name": "languages_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - }, - "languages_code_unique": { - "name": "languages_code_unique", - "nullsNotDistinct": false, - "columns": [ - "code" - ] - } - } - }, - "public.licenses": { - "name": "licenses", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "url": { - "name": "url", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "licenses_id_unique": { - "name": "licenses_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.notifications": { - "name": "notifications", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "action_id": { - "name": "action_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "actor_user_id": { - "name": "actor_user_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "target_user_id": { - "name": "target_user_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "target_resource_id": { - "name": "target_resource_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "target_collection_id": { - "name": "target_collection_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "notifications_action_id_actions_id_fk": { - "name": "notifications_action_id_actions_id_fk", - "tableFrom": "notifications", - "tableTo": "actions", - "columnsFrom": [ - "action_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "notifications_actor_user_id_users_id_fk": { - "name": "notifications_actor_user_id_users_id_fk", - "tableFrom": "notifications", - "tableTo": "users", - "columnsFrom": [ - "actor_user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "notifications_target_user_id_users_id_fk": { - "name": "notifications_target_user_id_users_id_fk", - "tableFrom": "notifications", - "tableTo": "users", - "columnsFrom": [ - "target_user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "notifications_target_resource_id_resources_id_fk": { - "name": "notifications_target_resource_id_resources_id_fk", - "tableFrom": "notifications", - "tableTo": "resources", - "columnsFrom": [ - "target_resource_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "notifications_target_collection_id_collections_id_fk": { - "name": "notifications_target_collection_id_collections_id_fk", - "tableFrom": "notifications", - "tableTo": "collections", - "columnsFrom": [ - "target_collection_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "notifications_id_unique": { - "name": "notifications_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.object_types": { - "name": "object_types", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "object_types_id_unique": { - "name": "object_types_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.reset_tickets": { - "name": "reset_tickets", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "token_hash": { - "name": "token_hash", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "expiration_date": { - "name": "expiration_date", - "type": "timestamp", - "primaryKey": false, - "notNull": true - }, - "token_used": { - "name": "token_used", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "valid_token": { - "name": "valid_token", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "reset_tickets_user_id_users_id_fk": { - "name": "reset_tickets_user_id_users_id_fk", - "tableFrom": "reset_tickets", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "reset_tickets_id_unique": { - "name": "reset_tickets_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.resource_educational_stages": { - "name": "resource_educational_stages", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "resource_id": { - "name": "resource_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "educational_stage_id": { - "name": "educational_stage_id", - "type": "integer", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "resource_educational_stages_resource_id_resources_id_fk": { - "name": "resource_educational_stages_resource_id_resources_id_fk", - "tableFrom": "resource_educational_stages", - "tableTo": "resources", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "resource_educational_stages_educational_stage_id_educational_stages_id_fk": { - "name": "resource_educational_stages_educational_stage_id_educational_stages_id_fk", - "tableFrom": "resource_educational_stages", - "tableTo": "educational_stages", - "columnsFrom": [ - "educational_stage_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "resource_educational_stages_id_unique": { - "name": "resource_educational_stages_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.resource_languages": { - "name": "resource_languages", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "resource_id": { - "name": "resource_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "language_id": { - "name": "language_id", - "type": "integer", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "resource_languages_resource_id_resources_id_fk": { - "name": "resource_languages_resource_id_resources_id_fk", - "tableFrom": "resource_languages", - "tableTo": "resources", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "resource_languages_language_id_languages_id_fk": { - "name": "resource_languages_language_id_languages_id_fk", - "tableFrom": "resource_languages", - "tableTo": "languages", - "columnsFrom": [ - "language_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "resource_languages_id_unique": { - "name": "resource_languages_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.resource_likes": { - "name": "resource_likes", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "resource_id": { - "name": "resource_id", - "type": "integer", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "resource_likes_user_id_users_id_fk": { - "name": "resource_likes_user_id_users_id_fk", - "tableFrom": "resource_likes", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "resource_likes_resource_id_resources_id_fk": { - "name": "resource_likes_resource_id_resources_id_fk", - "tableFrom": "resource_likes", - "tableTo": "resources", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "resource_likes_id_unique": { - "name": "resource_likes_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.resource_stats": { - "name": "resource_stats", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "views": { - "name": "views", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "downloads": { - "name": "downloads", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "likes": { - "name": "likes", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "shares": { - "name": "shares", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "score": { - "name": "score", - "type": "numeric", - "primaryKey": false, - "notNull": true, - "default": "'0.0'" - }, - "follows": { - "name": "follows", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "resource_stats_id_unique": { - "name": "resource_stats_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.resource_subjects": { - "name": "resource_subjects", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "resource_id": { - "name": "resource_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "subject_id": { - "name": "subject_id", - "type": "integer", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "resource_subjects_resource_id_resources_id_fk": { - "name": "resource_subjects_resource_id_resources_id_fk", - "tableFrom": "resource_subjects", - "tableTo": "resources", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "resource_subjects_subject_id_subjects_id_fk": { - "name": "resource_subjects_subject_id_subjects_id_fk", - "tableFrom": "resource_subjects", - "tableTo": "subjects", - "columnsFrom": [ - "subject_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "resource_subjects_id_unique": { - "name": "resource_subjects_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.resources": { - "name": "resources", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "author": { - "name": "author", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "bucket_key": { - "name": "bucket_key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "link": { - "name": "link", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "thumbnail": { - "name": "thumbnail", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "active": { - "name": "active", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "published_at": { - "name": "published_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "submitted_at": { - "name": "submitted_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "deleted_at": { - "name": "deleted_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "resource_stats_id": { - "name": "resource_stats_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "object_type_id": { - "name": "object_type_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "license_id": { - "name": "license_id", - "type": "integer", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "resources_user_id_users_id_fk": { - "name": "resources_user_id_users_id_fk", - "tableFrom": "resources", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "resources_resource_stats_id_resource_stats_id_fk": { - "name": "resources_resource_stats_id_resource_stats_id_fk", - "tableFrom": "resources", - "tableTo": "resource_stats", - "columnsFrom": [ - "resource_stats_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "resources_object_type_id_object_types_id_fk": { - "name": "resources_object_type_id_object_types_id_fk", - "tableFrom": "resources", - "tableTo": "object_types", - "columnsFrom": [ - "object_type_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "resources_license_id_licenses_id_fk": { - "name": "resources_license_id_licenses_id_fk", - "tableFrom": "resources", - "tableTo": "licenses", - "columnsFrom": [ - "license_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "resources_id_unique": { - "name": "resources_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - }, - "resources_bucket_key_unique": { - "name": "resources_bucket_key_unique", - "nullsNotDistinct": false, - "columns": [ - "bucket_key" - ] - }, - "resources_resource_stats_id_unique": { - "name": "resources_resource_stats_id_unique", - "nullsNotDistinct": false, - "columns": [ - "resource_stats_id" - ] - } - } - }, - "public.roles": { - "name": "roles", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "roles_id_unique": { - "name": "roles_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - }, - "roles_name_unique": { - "name": "roles_name_unique", - "nullsNotDistinct": false, - "columns": [ - "name" - ] - } - } - }, - "public.subjects": { - "name": "subjects", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "subjects_id_unique": { - "name": "subjects_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.submissions": { - "name": "submissions", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "is_accepted": { - "name": "is_accepted", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "justification": { - "name": "justification", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "resource_id": { - "name": "resource_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "submitter_id": { - "name": "submitter_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "curator_id": { - "name": "curator_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "answered_at": { - "name": "answered_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "q1": { - "name": "q1", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "q2": { - "name": "q2", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "q3": { - "name": "q3", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "q4": { - "name": "q4", - "type": "boolean", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "submissions_resource_id_resources_id_fk": { - "name": "submissions_resource_id_resources_id_fk", - "tableFrom": "submissions", - "tableTo": "resources", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "submissions_submitter_id_users_id_fk": { - "name": "submissions_submitter_id_users_id_fk", - "tableFrom": "submissions", - "tableTo": "users", - "columnsFrom": [ - "submitter_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "submissions_curator_id_users_id_fk": { - "name": "submissions_curator_id_users_id_fk", - "tableFrom": "submissions", - "tableTo": "users", - "columnsFrom": [ - "curator_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "submissions_id_unique": { - "name": "submissions_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.user_achievements": { - "name": "user_achievements", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "achievement_id": { - "name": "achievement_id", - "type": "integer", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "user_achievements_user_id_users_id_fk": { - "name": "user_achievements_user_id_users_id_fk", - "tableFrom": "user_achievements", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "user_achievements_achievement_id_users_id_fk": { - "name": "user_achievements_achievement_id_users_id_fk", - "tableFrom": "user_achievements", - "tableTo": "users", - "columnsFrom": [ - "achievement_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "user_achievements_id_unique": { - "name": "user_achievements_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.user_institutions": { - "name": "user_institutions", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "institution_id": { - "name": "institution_id", - "type": "integer", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "user_institutions_user_id_users_id_fk": { - "name": "user_institutions_user_id_users_id_fk", - "tableFrom": "user_institutions", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "user_institutions_institution_id_institutions_id_fk": { - "name": "user_institutions_institution_id_institutions_id_fk", - "tableFrom": "user_institutions", - "tableTo": "institutions", - "columnsFrom": [ - "institution_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "user_institutions_id_unique": { - "name": "user_institutions_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.user_items": { - "name": "user_items", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "item_id": { - "name": "item_id", - "type": "integer", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "user_items_user_id_users_id_fk": { - "name": "user_items_user_id_users_id_fk", - "tableFrom": "user_items", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "user_items_item_id_items_id_fk": { - "name": "user_items_item_id_items_id_fk", - "tableFrom": "user_items", - "tableTo": "items", - "columnsFrom": [ - "item_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "user_items_id_unique": { - "name": "user_items_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.user_roles": { - "name": "user_roles", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "role_id": { - "name": "role_id", - "type": "integer", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "user_roles_user_id_users_id_fk": { - "name": "user_roles_user_id_users_id_fk", - "tableFrom": "user_roles", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "user_roles_role_id_roles_id_fk": { - "name": "user_roles_role_id_roles_id_fk", - "tableFrom": "user_roles", - "tableTo": "roles", - "columnsFrom": [ - "role_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "user_roles_id_unique": { - "name": "user_roles_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.user_stats": { - "name": "user_stats", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "score": { - "name": "score", - "type": "numeric", - "primaryKey": false, - "notNull": true, - "default": "'0.0'" - }, - "likes": { - "name": "likes", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "likes_received": { - "name": "likes_received", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "follows": { - "name": "follows", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "followers": { - "name": "followers", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "collections": { - "name": "collections", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "submitted_resources": { - "name": "submitted_resources", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "approved_resources": { - "name": "approved_resources", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "reviewed_resources": { - "name": "reviewed_resources", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "comments": { - "name": "comments", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "user_stats_id_unique": { - "name": "user_stats_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.users": { - "name": "users", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "username": { - "name": "username", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "password": { - "name": "password", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "'sem descrição'" - }, - "institution": { - "name": "institution", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "'sem instituição'" - }, - "birthday": { - "name": "birthday", - "type": "timestamp", - "primaryKey": false, - "notNull": true - }, - "cpf": { - "name": "cpf", - "type": "varchar(11)", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "confirmed_at": { - "name": "confirmed_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "confirmation_sent_at": { - "name": "confirmation_sent_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "deleted_at": { - "name": "deleted_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "reactivated_at": { - "name": "reactivated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "active": { - "name": "active", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": true - }, - "user_stats_id": { - "name": "user_stats_id", - "type": "integer", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "users_user_stats_id_user_stats_id_fk": { - "name": "users_user_stats_id_user_stats_id_fk", - "tableFrom": "users", - "tableTo": "user_stats", - "columnsFrom": [ - "user_stats_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "users_id_unique": { - "name": "users_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - }, - "users_username_unique": { - "name": "users_username_unique", - "nullsNotDistinct": false, - "columns": [ - "username" - ] - }, - "users_email_unique": { - "name": "users_email_unique", - "nullsNotDistinct": false, - "columns": [ - "email" - ] - }, - "users_cpf_unique": { - "name": "users_cpf_unique", - "nullsNotDistinct": false, - "columns": [ - "cpf" - ] - }, - "users_user_stats_id_unique": { - "name": "users_user_stats_id_unique", - "nullsNotDistinct": false, - "columns": [ - "user_stats_id" - ] - } - } - } - }, - "enums": { - "public.state": { - "name": "state", - "schema": "public", - "values": [ - "active", - "inactive", - "under_review" - ] - } - }, - "schemas": {}, - "_meta": { - "columns": {}, - "schemas": {}, - "tables": {} - } -} \ No newline at end of file diff --git a/src/db/migrations/meta/_journal.json b/src/db/migrations/meta/_journal.json index d5e1531..fd42dad 100644 --- a/src/db/migrations/meta/_journal.json +++ b/src/db/migrations/meta/_journal.json @@ -5,43 +5,15 @@ { "idx": 0, "version": "7", - "when": 1732716257048, - "tag": "0000_secret_sharon_ventura", + "when": 1740147860395, + "tag": "0000_flawless_scarecrow", "breakpoints": true }, { "idx": 1, "version": "7", - "when": 1732716382536, - "tag": "0001_strange_famine", - "breakpoints": true - }, - { - "idx": 2, - "version": "7", - "when": 1732716630298, - "tag": "0002_sleepy_vin_gonzales", - "breakpoints": true - }, - { - "idx": 3, - "version": "7", - "when": 1738594390624, - "tag": "0003_tired_stone_men", - "breakpoints": true - }, - { - "idx": 4, - "version": "7", - "when": 1739363633612, - "tag": "0004_useful_paper_doll", - "breakpoints": true - }, - { - "idx": 5, - "version": "7", - "when": 1739370229565, - "tag": "0005_eager_darkstar", + "when": 1740406482014, + "tag": "0001_odd_valkyrie", "breakpoints": true } ] diff --git a/src/db/relations/user-collection.relation.ts b/src/db/relations/user-collection.relation.ts new file mode 100644 index 0000000..9e63a6d --- /dev/null +++ b/src/db/relations/user-collection.relation.ts @@ -0,0 +1,47 @@ +import { integer, pgTable, serial } from "drizzle-orm/pg-core"; +import { collectionTable, userTable } from "../schema"; +import { relations } from "drizzle-orm"; +import { createInsertSchema, createSelectSchema } from "drizzle-zod"; +import type { z } from "zod"; + +const userCollectionTable = pgTable('userCollections', { + id: serial('id').primaryKey() + .unique() + .notNull(), + user_id: integer("user_id") + .notNull() + .references(() => userTable.id, { onDelete: 'cascade' }), + collection_id: integer("collection_id") + .notNull() + .references(() => collectionTable.id, {onDelete: 'cascade'}) +}) + +export const userCollectionsRelations = relations(userCollectionTable, ({one}) => ({ + user: one(userTable, { + fields: [userCollectionTable.user_id], + references: [userTable.id] + }), + collection: one(collectionTable, { + fields: [userCollectionTable.collection_id], + references: [collectionTable.id] + }) +})) + +const userCollectionsModelSchema = createSelectSchema(userCollectionTable) +const userCollectionsDtoSchema = userCollectionsModelSchema +const userCollectionsInputSchema = createInsertSchema(userCollectionTable) +const userCollectionsUpdateSchema = userCollectionsInputSchema.partial().required({ user_id: true, collection_id: true}) + +export type userCollectionsModel = z.infer<typeof userCollectionsModelSchema> +export type userCollectionsDto = z.infer<typeof userCollectionsDtoSchema> +export type userCollectionsInput = z.infer<typeof userCollectionsInputSchema> +export type userCollectionsUpdate = z.infer<typeof userCollectionsUpdateSchema> + +export const userCollectionsSchemas = { + userCollectionsModelSchema, + userCollectionsDtoSchema, + userCollectionsInputSchema, + userCollectionsUpdateSchema, +} + +export default userCollectionTable diff --git a/src/db/repo/collections.repo.ts b/src/db/repo/collections.repo.ts index 15b4a86..44d1d67 100644 --- a/src/db/repo/collections.repo.ts +++ b/src/db/repo/collections.repo.ts @@ -7,6 +7,12 @@ import type { import db from ".."; import collectionTable, { collectionSchemas } from "../schema/collection.schema"; import { and, eq, isNull } from 'drizzle-orm' +import type { ResourceModel } from "../schema/resource.schema"; +import fs from 'fs'; +import path from 'path'; +import archiver from 'archiver'; +import { PassThrough } from "stream"; + @Service() export class CollectionRepo { @@ -114,4 +120,11 @@ export class CollectionRepo { .where(and(eq(collectionTable.user_id, id), eq(collectionTable.is_private, true))) ) } + + // async downloadCollection(collectionId: CollectionModel['id']): Promise <Buffer> { + // try { + + // fazer zip + // } + // } } \ No newline at end of file diff --git a/src/db/repo/user-collection.repo.ts b/src/db/repo/user-collection.repo.ts new file mode 100644 index 0000000..bf68f0a --- /dev/null +++ b/src/db/repo/user-collection.repo.ts @@ -0,0 +1,123 @@ +import { Service } from "typedi"; +import type { UserModel } from "../schema/user.schema"; +import type { CollectionModel } from "../schema/collection.schema"; +import db from ".."; +import userCollectionTable from "../relations/user-collection.relation"; +import { and, eq, inArray } from "drizzle-orm"; +import collectionTable from "../schema/collection.schema"; +import userTable from "../schema/user.schema"; + +@Service() +export class userCollectionsRepo { + async associateUserWithCollection(userId: UserModel['id'], collectionIds: CollectionModel['id'][]): Promise<void> { + try { + const existingAssociations = await db + .select({ + collection_id: userCollectionTable.collection_id, + }) + .from(userCollectionTable) + .where(eq(userCollectionTable.user_id, userId)) + .execute(); + + const existingCollectionIds = existingAssociations.map(row => row.collection_id); + + const newCollectionIds = collectionIds.filter(collectionId => !existingCollectionIds.includes(collectionId)); + + if (newCollectionIds.length > 0) { + const valuesToInsert = newCollectionIds.map(collectionId => ({ + user_id: userId, + collection_id: collectionId, + })); + + await db + .insert(userCollectionTable) + .values(valuesToInsert) + .onConflictDoNothing() + .execute(); + + console.log(`User ${userId} associated with new collections: ${newCollectionIds.join(', ')}`); + } else { + console.log(`No new collections to associate with user ${userId}`); + } + } catch (error) { + console.error("Error associating user with collection", error); + } + } + + async getCollectionsByUser(userId: UserModel['id']): Promise<Partial<CollectionModel>[]> { + try { + const collections = await db + .select({ + id: collectionTable.id, + name: collectionTable.name, + }) + .from(collectionTable) + .innerJoin(userCollectionTable, eq(userCollectionTable.collection_id, collectionTable.id)) + .where(eq(userCollectionTable.user_id, userId)) + .execute(); + + return collections; + } catch (error) { + console.log("Error fetching collections by user", error); + throw error; + } + } + + async removeCollectionsFromUser(userId: UserModel['id'], collectionIds: CollectionModel['id'][]): Promise<void> { + try { + await db + .delete(userCollectionTable) + .where( + and( + eq(userCollectionTable.user_id, userId), + inArray(userCollectionTable.collection_id, collectionIds), + ) + ) + .execute(); + + console.log(`Collections removed from user${userId}: ${collectionIds.join(', ')}`); + } catch (error) { + console.error("error removing collections from users", error); + throw error; + } + } + + async isAssociationExists(userId: UserModel['id'], collectionId: CollectionModel['id']): Promise<boolean> { + try { + const result = await db + .select() + .from(userCollectionTable) + .where( + and( + eq(userCollectionTable.user_id, userId), + eq(userCollectionTable.collection_id, collectionId) + ) + ) + .execute(); + + return result.length > 0; + } catch (error) { + console.error("error checking if association exists", error); + throw error; + } + } + + async getUsersByCollection(collectionId: CollectionModel['id']): Promise<UserModel[]> { + try { + const users = await db + .select({ + id: userTable.id, + name: userTable.name, + }) + .from(userCollectionTable) + .innerJoin(userTable, eq(userCollectionTable.user_id, userTable.id)) + .where(eq(userCollectionTable.collection_id, collectionId)) + .execute(); + + return users; + } catch (error) { + console.error("Error fetching users by collection", error); + throw error; + } + } +} \ No newline at end of file diff --git a/src/db/schema/index.ts b/src/db/schema/index.ts index db2002d..d1e4393 100644 --- a/src/db/schema/index.ts +++ b/src/db/schema/index.ts @@ -34,6 +34,7 @@ import userItemRelationTable from '../relations/user-item.relation' import stateEnum from './stateEnum.schema' import commentsTable from './comments.schema' import commentReplyTable from './comment-reply.schema' +import userCollectionTable from '../relations/user-collection.relation' export { userTable, @@ -70,7 +71,8 @@ export { userItemRelationTable, stateEnum, commentsTable, - commentReplyTable + commentReplyTable, + userCollectionTable, } export const tables = [ @@ -103,6 +105,6 @@ export const tables = [ notificationRelationTable, userItemRelationTable, commentsTable, - commentReplyTable - + commentReplyTable, + userCollectionTable, ] diff --git a/src/db/seed.ts b/src/db/seed.ts index e4ae0e4..a6e38e3 100644 --- a/src/db/seed.ts +++ b/src/db/seed.ts @@ -21,12 +21,12 @@ for (const table of schema.tables) { await resetTable(db, table) } +// A ordem do userStatsSeed e userSeed deve ser respeitada (stats primeiro), caso contrário o bun db:seed não funcionará await seeds.userStatsSeed(db) await seeds.userSeed(db) await seeds.objectTypeSeed(db) await seeds.licenseSeed(db) await seeds.resourceStatsSeed(db) - await seeds.resourceSeed(db) await seeds.collectionStatsSeed(db) await seeds.collectionSeed(db) @@ -50,5 +50,6 @@ await seeds.itemsSeed(db) await seeds.userAchievementsSeed(db) await seeds.actionSeed(db) await seeds.commentsSeed(db) +await seeds.userCollectionsSeed(db) await connection.end() diff --git a/src/db/seeds/collection-stats.seed.ts b/src/db/seeds/collection-stats.seed.ts index 6fdf241..c611b8c 100644 --- a/src/db/seeds/collection-stats.seed.ts +++ b/src/db/seeds/collection-stats.seed.ts @@ -8,6 +8,7 @@ export default async function seed(db:db) { const collectionStatsData: CollectionStatsInput[] = [ { + collection_id: 1, views: 100, downloads: 50, likes: 20, diff --git a/src/db/seeds/index.ts b/src/db/seeds/index.ts index 3e9c104..29659ff 100644 --- a/src/db/seeds/index.ts +++ b/src/db/seeds/index.ts @@ -1,5 +1,6 @@ -export { default as userSeed } from './user.seed' export { default as userStatsSeed } from './user-stats.seed' +export { default as userSeed } from './user.seed' +export { default as userCollectionsSeed } from './user-collection.seed' export { default as resourceSeed } from './resource.seed' export { default as resourceStatsSeed } from './resourceStats.seed' export { default as collectionSeed } from './collections.seed' @@ -25,4 +26,4 @@ export { default as achievementSeed } from './achievement.seed' export { default as itemsSeed } from './items.seed' export { default as userAchievementsSeed } from './user-achievements.seed' export { default as actionSeed } from './action.seed' -export { default as commentsSeed } from './comments.seed' +export { default as commentsSeed } from './comments.seed' \ No newline at end of file diff --git a/src/db/seeds/resource-language.seed.ts b/src/db/seeds/resource-language.seed.ts index d76927d..115fd5b 100644 --- a/src/db/seeds/resource-language.seed.ts +++ b/src/db/seeds/resource-language.seed.ts @@ -9,11 +9,11 @@ export default async function seed(db: db) { const resourceLanguageData: ResourceLanguagesInput[] = [ { - resource_id: 1, + resource_id: 2, language_id: 1 }, { - resource_id: 1, + resource_id: 2, language_id: 2 }, { diff --git a/src/db/seeds/user-collection.seed.ts b/src/db/seeds/user-collection.seed.ts new file mode 100644 index 0000000..6333dcd --- /dev/null +++ b/src/db/seeds/user-collection.seed.ts @@ -0,0 +1,38 @@ +import type db from '@/db' +import userCollectionTable, { type userCollectionsInput } from '../relations/user-collection.relation' + + +export default async function seed(db: db) { + await db.insert(userCollectionTable).values(userCollectionsData) +} + +const userCollectionsData: userCollectionsInput[] = [ + { + user_id: 1, + collection_id: 1 + }, + { + user_id: 1, + collection_id: 2 + }, + { + user_id: 1, + collection_id: 3 + }, + { + user_id: 2, + collection_id: 1 + }, + { + user_id: 2, + collection_id: 2 + }, + { + user_id: 3, + collection_id: 2 + }, + { + user_id: 3, + collection_id: 3 + } +] diff --git a/src/db/seeds/user-stats.seed.ts b/src/db/seeds/user-stats.seed.ts index 47a6a08..712a51e 100644 --- a/src/db/seeds/user-stats.seed.ts +++ b/src/db/seeds/user-stats.seed.ts @@ -8,7 +8,6 @@ export default async function seed(db: db) { const usersStatsData: UserStatsInput[] = [ { - }, { diff --git a/src/index.ts b/src/index.ts index 9061de7..509f3df 100644 --- a/src/index.ts +++ b/src/index.ts @@ -42,6 +42,7 @@ import { swaggerUI } from '@hono/swagger-ui' import { OpenAPIHono } from "@hono/zod-openapi"; import { commentsRouter, publicCommentsRoute } from './routes/comments.route' import { publicCommentsReplyRoute, commentReplyRouter } from './routes/comment-reply.route' +import { publicUserCollectionsRoutes, userCollectionsRoute } from './routes/user-collection.route' @@ -117,6 +118,7 @@ app .route('/userAchievements', publicUserAchievementsRoute) .route('/comments', publicCommentsRoute) .route('/replyComment', publicCommentsReplyRoute) + .route('/userCollections', publicUserCollectionsRoutes) //rotas que precisam de token app .basePath('/api') @@ -152,6 +154,7 @@ app .route('/user-item', userItemRouter) .route('/comments', commentsRouter) .route('/replyComment', commentReplyRouter) + .route('/userCollections', userCollectionsRoute) export default app export type AppType = typeof app diff --git a/src/routes/user-collection.route.ts b/src/routes/user-collection.route.ts new file mode 100644 index 0000000..108435e --- /dev/null +++ b/src/routes/user-collection.route.ts @@ -0,0 +1,120 @@ +import { UserCollectionsService } from "@/services/user-collection.service"; +import Container from "typedi"; +import { z } from "zod"; +import { honoWithJwt } from ".."; +import { zValidator } from "@hono/zod-validator"; +import { createApexError, HttpStatus } from "@/services/error.service"; +import { Hono } from "hono"; + +const associateSchema = z.object({ + userId: z.number(), + collectionIds: z.array(z.number()), +}) + +const service = Container.get(UserCollectionsService); + +export const userCollectionsRoute = honoWithJwt() + .post('/associate', zValidator('json', associateSchema), + async (c) => { + try { + const {userId, collectionIds } = await c.req.valid('json'); + await service.associateUserWithCollections(userId, collectionIds); + return c.json({ message: 'Collections associates succesfully'}, HttpStatus.OK); + } catch (e) { + return c.json( + createApexError({ + status: 'error', + message: 'Failed to associate collections', + code: HttpStatus.BAD_REQUEST, + path: c.req.routePath, + suggestion: 'Ensure the user and collection ids are valid', + }), + HttpStatus.BAD_REQUEST + ) + } + } + ) + .post('/:userId/delete/:collectionId', + async (c) => { + try { + const userid = +c.req.param('userId'); + const collectionId = +c.req.param('collectionId'); + await service.removeCollectionsFromUser(userid, [collectionId]); + return c.json({ message: 'Collections removed succesfully'}, HttpStatus.OK); + } catch (e) { + return c.json ( + createApexError({ + status: 'error', + message: 'Failed to remove collections', + code: HttpStatus.BAD_REQUEST, + path: c.req.routePath, + suggestion: 'Ensure the user and collection ids are valid', + }), + HttpStatus.BAD_REQUEST + ) + } + } + ) + +export const publicUserCollectionsRoutes = new Hono() + .get('/:userId/collections', + async (c) => { + try { + const userId = +c.req.param('userId'); + const collections = await service.getCollectionByUser(userId); + return c.json(collections, HttpStatus.OK); + } catch (e) { + return c.json( + createApexError({ + status: 'error', + message: 'Failed to fetch collections', + code: HttpStatus.BAD_REQUEST, + path: c.req.routePath, + suggestion: 'Ensure the user id is valid', + }), + HttpStatus.BAD_REQUEST + ) + } + } + ) + .get('/:userId/collections/:collectionId/exists', + async (c) => { + try { + const userId = +c.req.param('userId'); + const collectionId = +c.req.param('collectionId'); + const exists = await service.isAssociationExists(userId, collectionId); + return c.json( {exists}, HttpStatus.OK); + } catch (e) { + return c.json( + createApexError({ + status: 'error', + message: 'Failed to check association', + code: HttpStatus.BAD_REQUEST, + path: c.req.routePath, + suggestion: 'Check the input and try again', + }), + HttpStatus.BAD_REQUEST + ); + } + } + ) + .get('/collection/:collectionId/users', + async (c) => { + try { + const collectionId = +c.req.param('collectionId'); + const users = await service.getUsersByCollection(collectionId); + return c.json({ users }, HttpStatus.OK); + } catch (e) { + return c.json( + createApexError({ + status: 'error', + message: 'Failed to fetch users', + code: HttpStatus.BAD_REQUEST, + path: c.req.routePath, + suggestion: 'Check the input and try again', + }), + HttpStatus.BAD_REQUEST + ); + } + } + ) diff --git a/src/services/user-collection.service.ts b/src/services/user-collection.service.ts new file mode 100644 index 0000000..99cad76 --- /dev/null +++ b/src/services/user-collection.service.ts @@ -0,0 +1,30 @@ +import { userCollectionsRepo } from "@/db/repo/user-collection.repo"; +import type { CollectionModel } from "@/db/schema/collection.schema"; +import type { UserModel } from "@/db/schema/user.schema"; +import { Inject, Service } from "typedi"; + +@Service() +export class UserCollectionsService { + @Inject() + private readonly repo: userCollectionsRepo; + + async associateUserWithCollections(userId: UserModel['id'], collectionIds: CollectionModel['id'][]): Promise<void> { + await this.repo.associateUserWithCollection(userId, collectionIds); + } + + async getCollectionByUser(userId: UserModel['id']): Promise<Partial<CollectionModel>[]> { + return this.repo.getCollectionsByUser(userId); + } + + async removeCollectionsFromUser(userId: UserModel['id'], collectionIds: CollectionModel['id'][]): Promise<void> { + await this.repo.removeCollectionsFromUser(userId, collectionIds); + } + + async isAssociationExists(userId: UserModel['id'], collectionId: CollectionModel['id']): Promise<boolean> { + return this.repo.isAssociationExists(userId, collectionId); + } + + async getUsersByCollection(collectionId: CollectionModel['id']): Promise<UserModel[]> { + return this.repo.getUsersByCollection(collectionId); + } +} \ No newline at end of file -- GitLab