11// Copyright 2024 the JSR authors. All rights reserved. MIT license.
22use hyper:: { Body , Request } ;
33use routerify:: prelude:: * ;
4- use serde:: Serialize ;
4+ use serde:: { Serialize , Deserialize } ; // 添加 Deserialize
5+ use tracing:: instrument;
56
67use crate :: {
78 db:: { Change , Database } ,
89 util:: { pagination, ApiResult } ,
910} ;
1011
11-
12- #[ derive( Serialize ) ]
12+ #[ derive( Serialize , Deserialize ) ] // 添加 Deserialize
1313pub struct ApiChange {
1414 pub seq : i64 ,
1515 pub r#type : String ,
@@ -28,9 +28,130 @@ impl From<Change> for ApiChange {
2828 }
2929}
3030
31+ #[ instrument( name = "GET /api/_changes" , skip( req) , err) ]
3132pub async fn list_changes ( req : Request < Body > ) -> ApiResult < Vec < ApiChange > > {
3233 let db = req. data :: < Database > ( ) . unwrap ( ) ;
3334 let ( start, limit) = pagination ( & req) ;
3435 let changes = db. list_changes ( start, limit) . await ?;
3536 Ok ( changes. into_iter ( ) . map ( ApiChange :: from) . collect ( ) )
3637}
38+
39+
40+ #[ cfg( test) ]
41+ mod tests {
42+ use super :: ApiChange ;
43+ use crate :: ids:: PackageName ;
44+ use crate :: ids:: ScopeName ;
45+ use crate :: util:: test:: ApiResultExt ;
46+ use crate :: util:: test:: TestSetup ;
47+ use crate :: db:: ChangeType ;
48+ use serde_json:: json;
49+
50+ #[ tokio:: test]
51+ async fn list_empty_changes ( ) {
52+ let mut t = TestSetup :: new ( ) . await ;
53+
54+ let changes = t
55+ . http ( )
56+ . get ( "/api/_changes" )
57+ . call ( )
58+ . await
59+ . unwrap ( )
60+ . expect_ok :: < Vec < ApiChange > > ( )
61+ . await ;
62+
63+ assert ! ( changes. is_empty( ) ) ;
64+ }
65+
66+ #[ tokio:: test]
67+ async fn list_single_change ( ) {
68+ let mut t = TestSetup :: new ( ) . await ;
69+
70+ t. ephemeral_database . create_change (
71+ ChangeType :: PackageVersionAdded ,
72+ & ScopeName :: new ( "test-scope" . to_string ( ) ) . unwrap ( ) ,
73+ & PackageName :: new ( "test-package" . to_string ( ) ) . unwrap ( ) ,
74+ json ! ( {
75+ "version" : "1.0.0"
76+ } ) ,
77+ ) . await . unwrap ( ) ;
78+
79+ let changes = t
80+ . http ( )
81+ . get ( "/api/_changes" )
82+ . call ( )
83+ . await
84+ . unwrap ( )
85+ . expect_ok :: < Vec < ApiChange > > ( )
86+ . await ;
87+
88+ assert_eq ! ( changes. len( ) , 1 ) ;
89+ let change = & changes[ 0 ] ;
90+ assert_eq ! ( change. r#type, ChangeType :: PackageVersionAdded . to_string( ) ) ;
91+ assert_eq ! ( change. id, "@jsr/test-scope__test-package" ) ;
92+ assert_eq ! ( change. changes[ "version" ] , "1.0.0" ) ;
93+ }
94+
95+ #[ tokio:: test]
96+ async fn list_changes_pagination ( ) {
97+ let mut t = TestSetup :: new ( ) . await ;
98+
99+ // Create two changes
100+ t. ephemeral_database . create_change (
101+ ChangeType :: PackageVersionAdded ,
102+ & ScopeName :: new ( "test-scope" . to_string ( ) ) . unwrap ( ) ,
103+ & PackageName :: new ( "test-package-1" . to_string ( ) ) . unwrap ( ) ,
104+ json ! ( {
105+ "name" : "test-package-1" ,
106+ } ) ,
107+ ) . await . unwrap ( ) ;
108+
109+ t. ephemeral_database . create_change (
110+ ChangeType :: PackageVersionAdded ,
111+ & ScopeName :: new ( "test-scope" . to_string ( ) ) . unwrap ( ) ,
112+ & PackageName :: new ( "test-package-2" . to_string ( ) ) . unwrap ( ) ,
113+ json ! ( {
114+ "version" : "1.0.0" ,
115+ } ) ,
116+ ) . await . unwrap ( ) ;
117+
118+ // Test limit parameter
119+ let changes = t
120+ . http ( )
121+ . get ( "/api/_changes?limit=1&since=0" )
122+ . call ( )
123+ . await
124+ . unwrap ( )
125+ . expect_ok :: < Vec < ApiChange > > ( )
126+ . await ;
127+
128+ assert_eq ! ( changes. len( ) , 1 ) ;
129+ assert_eq ! ( changes[ 0 ] . id, "@jsr/test-scope__test-package-1" ) ;
130+
131+ // Test since parameter
132+ let changes = t
133+ . http ( )
134+ . get ( & format ! ( "/api/_changes?since={}" , changes[ 0 ] . seq) )
135+ . call ( )
136+ . await
137+ . unwrap ( )
138+ . expect_ok :: < Vec < ApiChange > > ( )
139+ . await ;
140+
141+ assert_eq ! ( changes. len( ) , 1 ) ;
142+ assert_eq ! ( changes[ 0 ] . id, "@jsr/test-scope__test-package-2" ) ;
143+
144+ // Test since + limit combination
145+ let changes = t
146+ . http ( )
147+ . get ( "/api/_changes?since=0&limit=1" )
148+ . call ( )
149+ . await
150+ . unwrap ( )
151+ . expect_ok :: < Vec < ApiChange > > ( )
152+ . await ;
153+
154+ assert_eq ! ( changes. len( ) , 1 ) ;
155+ assert_eq ! ( changes[ 0 ] . id, "@jsr/test-scope__test-package-1" ) ;
156+ }
157+ }
0 commit comments