Constellation, Spacedust, Slingshot, UFOs: atproto crates and services for microcosm
0

Configure Feed

Select the types of activity you want to include in your feed.

get multiple collections

+54 -35
+54 -35
ufos/src/server.rs
··· 82 82 } 83 83 84 84 #[derive(Debug, Deserialize, JsonSchema)] 85 - struct CollectionQuery { 85 + struct CollectionsQuery { 86 86 collection: String, // JsonSchema not implemented for Nsid :( 87 + } 88 + impl CollectionsQuery { 89 + fn to_multiple_nsids(&self) -> Result<Vec<Nsid>, String> { 90 + let mut out = Vec::with_capacity(self.collection.len()); 91 + for collection in self.collection.split(',') { 92 + let Ok(nsid) = Nsid::new(collection.to_string()) else { 93 + return Err(format!("collection {collection:?} was not a valid NSID")); 94 + }; 95 + out.push(nsid); 96 + } 97 + Ok(out) 98 + } 87 99 } 88 100 #[derive(Debug, Serialize, JsonSchema)] 89 101 struct ApiRecord { ··· 111 123 } 112 124 } 113 125 /// Get recent records by collection 126 + /// 127 + /// Multiple collections are supported. they will be delivered in one big array with no 128 + /// specified order. 114 129 #[endpoint { 115 130 method = GET, 116 131 path = "/records", 117 132 }] 118 133 async fn get_records_by_collection( 119 134 ctx: RequestContext<Context>, 120 - collection_query: Query<CollectionQuery>, 135 + collection_query: Query<CollectionsQuery>, 121 136 ) -> OkCorsResponse<Vec<ApiRecord>> { 122 - let Ok(collection) = Nsid::new(collection_query.into_inner().collection) else { 123 - return Err(HttpError::for_bad_request( 124 - None, 125 - "collection must be an NSID".to_string(), 126 - )); 127 - }; 128 137 let Context { storage, .. } = ctx.context(); 129 - let records = storage 130 - .get_collection_records(&collection, 100) 131 - .await 132 - .map_err(|e| HttpError::for_internal_error(e.to_string()))?; 138 + 139 + let collections = collection_query 140 + .into_inner() 141 + .to_multiple_nsids() 142 + .map_err(|reason| HttpError::for_bad_request(None, reason))?; 133 143 134 - if records.is_empty() { 135 - return Err(HttpError::for_not_found( 136 - None, 137 - format!("no saved records for collection {collection:?}"), 138 - )); 144 + let mut api_records = Vec::new(); 145 + 146 + // TODO: set up multiple db iterators and iterate them together with merge sort 147 + for collection in &collections { 148 + let records = storage 149 + .get_collection_records(collection, 100) 150 + .await 151 + .map_err(|e| HttpError::for_internal_error(e.to_string()))?; 152 + 153 + for record in records { 154 + let api_record = ApiRecord::from_create_record(record, collection); 155 + api_records.push(api_record); 156 + } 139 157 } 140 158 141 - let api_records = records 142 - .into_iter() 143 - .map(|r| ApiRecord::from_create_record(r, &collection)) 144 - .collect(); 145 - 146 159 ok_cors(api_records) 147 160 } 148 161 ··· 153 166 }] 154 167 async fn get_records_total_seen( 155 168 ctx: RequestContext<Context>, 156 - collection_query: Query<CollectionQuery>, 157 - ) -> OkCorsResponse<u64> { 158 - let Ok(collection) = Nsid::new(collection_query.into_inner().collection) else { 159 - return Err(HttpError::for_bad_request( 160 - None, 161 - "collection must be an NSID".to_string(), 162 - )); 163 - }; 169 + collection_query: Query<CollectionsQuery>, 170 + ) -> OkCorsResponse<HashMap<String, u64>> { 164 171 let Context { storage, .. } = ctx.context(); 165 - let total = storage 166 - .get_collection_total_seen(&collection) 167 - .await 168 - .map_err(|e| HttpError::for_internal_error(format!("boooo: {e:?}")))?; 172 + 173 + let collections = collection_query 174 + .into_inner() 175 + .to_multiple_nsids() 176 + .map_err(|reason| HttpError::for_bad_request(None, reason))?; 169 177 170 - ok_cors(total) 178 + let mut seen_by_collection = HashMap::with_capacity(collections.len()); 179 + 180 + for collection in &collections { 181 + let total = storage 182 + .get_collection_total_seen(collection) 183 + .await 184 + .map_err(|e| HttpError::for_internal_error(format!("boooo: {e:?}")))?; 185 + 186 + seen_by_collection.insert(collection.to_string(), total); 187 + } 188 + 189 + ok_cors(seen_by_collection) 171 190 } 172 191 173 192 /// Get top collections