Alternative ATProto PDS implementation

move account data to per-actor db

Changed files
+418 -332
src
account_manager
actor_store
apis
com
atproto
+16 -4
src/account_manager/helpers/account.rs
··· 257 257 deadpool_diesel::Manager<SqliteConnection>, 258 258 deadpool_diesel::sqlite::Object, 259 259 >, 260 + actor_db: &deadpool_diesel::Pool< 261 + deadpool_diesel::Manager<SqliteConnection>, 262 + deadpool_diesel::sqlite::Object, 263 + >, 260 264 ) -> Result<()> { 265 + use crate::schema::actor_store::repo_root::dsl as RepoRootSchema; 261 266 use crate::schema::pds::email_token::dsl as EmailTokenSchema; 262 267 use crate::schema::pds::refresh_token::dsl as RefreshTokenSchema; 263 - use crate::schema::pds::repo_root::dsl as RepoRootSchema; 264 268 269 + let did_clone = did.to_owned(); 270 + _ = actor_db 271 + .get() 272 + .await? 273 + .interact(move |conn| { 274 + delete(RepoRootSchema::repo_root) 275 + .filter(RepoRootSchema::did.eq(&did_clone)) 276 + .execute(conn) 277 + }) 278 + .await 279 + .expect("Failed to delete actor")?; 265 280 let did = did.to_owned(); 266 281 _ = db 267 282 .get() 268 283 .await? 269 284 .interact(move |conn| { 270 - _ = delete(RepoRootSchema::repo_root) 271 - .filter(RepoRootSchema::did.eq(&did)) 272 - .execute(conn)?; 273 285 _ = delete(EmailTokenSchema::email_token) 274 286 .filter(EmailTokenSchema::did.eq(&did)) 275 287 .execute(conn)?;
+3 -5
src/account_manager/helpers/repo.rs
··· 4 4 //! Modified for SQLite backend 5 5 use anyhow::Result; 6 6 use cidv10::Cid; 7 + use deadpool_diesel::{Manager, Pool, sqlite::Object}; 7 8 use diesel::*; 8 9 9 10 pub async fn update_root( 10 11 did: String, 11 12 cid: Cid, 12 13 rev: String, 13 - db: &deadpool_diesel::Pool< 14 - deadpool_diesel::Manager<SqliteConnection>, 15 - deadpool_diesel::sqlite::Object, 16 - >, 14 + db: &Pool<Manager<SqliteConnection>, Object>, 17 15 ) -> Result<()> { 18 16 // @TODO balance risk of a race in the case of a long retry 19 - use crate::schema::pds::repo_root::dsl as RepoRootSchema; 17 + use crate::schema::actor_store::repo_root::dsl as RepoRootSchema; 20 18 21 19 let now = rsky_common::now(); 22 20
+53 -6
src/account_manager/mod.rs
··· 2 2 //! blacksky-algorithms/rsky is licensed under the Apache License 2.0 3 3 //! 4 4 //! Modified for SQLite backend 5 + use crate::ActorPools; 5 6 use crate::account_manager::helpers::account::{ 6 7 AccountStatus, ActorAccount, AvailabilityFlags, GetAccountAdminStatusOutput, 7 8 }; ··· 16 17 use chrono::DateTime; 17 18 use chrono::offset::Utc as UtcOffset; 18 19 use cidv10::Cid; 20 + use deadpool_diesel::sqlite::Pool; 19 21 use diesel::*; 20 22 use futures::try_join; 21 23 use helpers::{account, auth, email_token, invite, password, repo}; ··· 131 133 } 132 134 } 133 135 134 - pub async fn create_account(&self, opts: CreateAccountOpts) -> Result<(String, String)> { 136 + pub async fn create_account( 137 + &self, 138 + opts: CreateAccountOpts, 139 + actor_pools: &mut std::collections::HashMap<String, ActorPools>, 140 + ) -> Result<(String, String)> { 135 141 let CreateAccountOpts { 136 142 did, 137 143 handle, ··· 172 178 } 173 179 invite::record_invite_use(did.clone(), invite_code, now, &self.db).await?; 174 180 auth::store_refresh_token(refresh_payload, None, &self.db).await?; 175 - repo::update_root(did, repo_cid, repo_rev, &self.db).await?; 181 + 182 + let did_path = did 183 + .strip_prefix("did:plc:") 184 + .ok_or_else(|| anyhow::anyhow!("Invalid DID"))?; 185 + let path_repo = format!("sqlite://{}", did_path); 186 + let actor_repo_pool = 187 + crate::establish_pool(path_repo.as_str()).expect("Failed to establish pool"); 188 + let path_blob = path_repo.replace("repo", "blob"); 189 + let actor_blob_pool = crate::establish_pool(&path_blob).expect("Failed to establish pool"); 190 + let actor_pool = ActorPools { 191 + repo: actor_repo_pool, 192 + blob: actor_blob_pool, 193 + }; 194 + actor_pools 195 + .insert(did.clone(), actor_pool) 196 + .expect("Failed to insert actor pools"); 197 + let db = actor_pools 198 + .get(&did) 199 + .ok_or_else(|| anyhow::anyhow!("Actor not found"))? 200 + .repo 201 + .clone(); 202 + repo::update_root(did, repo_cid, repo_rev, &db).await?; 176 203 Ok((access_jwt, refresh_jwt)) 177 204 } 178 205 ··· 183 210 account::get_account_admin_status(did, &self.db).await 184 211 } 185 212 186 - pub async fn update_repo_root(&self, did: String, cid: Cid, rev: String) -> Result<()> { 187 - repo::update_root(did, cid, rev, &self.db).await 213 + pub async fn update_repo_root( 214 + &self, 215 + did: String, 216 + cid: Cid, 217 + rev: String, 218 + actor_pools: &std::collections::HashMap<String, ActorPools>, 219 + ) -> Result<()> { 220 + let db = actor_pools 221 + .get(&did) 222 + .ok_or_else(|| anyhow::anyhow!("Actor not found"))? 223 + .repo 224 + .clone(); 225 + repo::update_root(did, cid, rev, &db).await 188 226 } 189 227 190 - pub async fn delete_account(&self, did: &str) -> Result<()> { 191 - account::delete_account(did, &self.db).await 228 + pub async fn delete_account( 229 + &self, 230 + did: &str, 231 + actor_pools: &std::collections::HashMap<String, ActorPools>, 232 + ) -> Result<()> { 233 + let db = actor_pools 234 + .get(did) 235 + .ok_or_else(|| anyhow::anyhow!("Actor not found"))? 236 + .repo 237 + .clone(); 238 + account::delete_account(did, &self.db, &db).await 192 239 } 193 240 194 241 pub async fn takedown_account(&self, did: &str, takedown: StatusAttr) -> Result<()> {
+16 -16
src/actor_store/blob.rs
··· 4 4 //! 5 5 //! Modified for SQLite backend 6 6 7 - use crate::models::pds as models; 7 + use crate::models::actor_store as models; 8 8 use anyhow::{Result, bail}; 9 9 use cidv10::Cid; 10 10 use diesel::dsl::{count_distinct, exists, not}; ··· 67 67 68 68 /// Get metadata for a blob by CID 69 69 pub async fn get_blob_metadata(&self, cid: Cid) -> Result<GetBlobMetadataOutput> { 70 - use crate::schema::pds::blob::dsl as BlobSchema; 70 + use crate::schema::actor_store::blob::dsl as BlobSchema; 71 71 72 72 let did = self.did.clone(); 73 73 let found = self ··· 112 112 113 113 /// Get all records that reference a specific blob 114 114 pub async fn get_records_for_blob(&self, cid: Cid) -> Result<Vec<String>> { 115 - use crate::schema::pds::record_blob::dsl as RecordBlobSchema; 115 + use crate::schema::actor_store::record_blob::dsl as RecordBlobSchema; 116 116 117 117 let did = self.did.clone(); 118 118 let res = self ··· 169 169 170 170 /// Track a blob that hasn't been associated with any records yet 171 171 pub async fn track_untethered_blob(&self, metadata: BlobMetadata) -> Result<BlobRef> { 172 - use crate::schema::pds::blob::dsl as BlobSchema; 172 + use crate::schema::actor_store::blob::dsl as BlobSchema; 173 173 174 174 let did = self.did.clone(); 175 175 self.db.get().await?.interact(move |conn| { ··· 254 254 255 255 /// Delete blobs that are no longer referenced by any records 256 256 pub async fn delete_dereferenced_blobs(&self, writes: Vec<PreparedWrite>) -> Result<()> { 257 - use crate::schema::pds::blob::dsl as BlobSchema; 258 - use crate::schema::pds::record_blob::dsl as RecordBlobSchema; 257 + use crate::schema::actor_store::blob::dsl as BlobSchema; 258 + use crate::schema::actor_store::record_blob::dsl as RecordBlobSchema; 259 259 260 260 // Extract URIs 261 261 let uris: Vec<String> = writes ··· 386 386 387 387 /// Verify a blob and make it permanent 388 388 pub async fn verify_blob_and_make_permanent(&self, blob: PreparedBlobRef) -> Result<()> { 389 - use crate::schema::pds::blob::dsl as BlobSchema; 389 + use crate::schema::actor_store::blob::dsl as BlobSchema; 390 390 391 391 let found = self 392 392 .db ··· 433 433 434 434 /// Associate a blob with a record 435 435 pub async fn associate_blob(&self, blob: PreparedBlobRef, record_uri: String) -> Result<()> { 436 - use crate::schema::pds::record_blob::dsl as RecordBlobSchema; 436 + use crate::schema::actor_store::record_blob::dsl as RecordBlobSchema; 437 437 438 438 let cid = blob.cid.to_string(); 439 439 let did = self.did.clone(); ··· 460 460 461 461 /// Count all blobs for this actor 462 462 pub async fn blob_count(&self) -> Result<i64> { 463 - use crate::schema::pds::blob::dsl as BlobSchema; 463 + use crate::schema::actor_store::blob::dsl as BlobSchema; 464 464 465 465 let did = self.did.clone(); 466 466 self.db ··· 479 479 480 480 /// Count blobs associated with records 481 481 pub async fn record_blob_count(&self) -> Result<i64> { 482 - use crate::schema::pds::record_blob::dsl as RecordBlobSchema; 482 + use crate::schema::actor_store::record_blob::dsl as RecordBlobSchema; 483 483 484 484 let did = self.did.clone(); 485 485 self.db ··· 501 501 &self, 502 502 opts: ListMissingBlobsOpts, 503 503 ) -> Result<Vec<ListMissingBlobsRefRecordBlob>> { 504 - use crate::schema::pds::blob::dsl as BlobSchema; 505 - use crate::schema::pds::record_blob::dsl as RecordBlobSchema; 504 + use crate::schema::actor_store::blob::dsl as BlobSchema; 505 + use crate::schema::actor_store::record_blob::dsl as RecordBlobSchema; 506 506 507 507 let did = self.did.clone(); 508 508 self.db ··· 563 563 564 564 /// List all blobs with optional filtering 565 565 pub async fn list_blobs(&self, opts: ListBlobsOpts) -> Result<Vec<String>> { 566 - use crate::schema::pds::record::dsl as RecordSchema; 567 - use crate::schema::pds::record_blob::dsl as RecordBlobSchema; 566 + use crate::schema::actor_store::record::dsl as RecordSchema; 567 + use crate::schema::actor_store::record_blob::dsl as RecordBlobSchema; 568 568 569 569 let ListBlobsOpts { 570 570 since, ··· 617 617 618 618 /// Get the takedown status of a blob 619 619 pub async fn get_blob_takedown_status(&self, cid: Cid) -> Result<Option<StatusAttr>> { 620 - use crate::schema::pds::blob::dsl as BlobSchema; 620 + use crate::schema::actor_store::blob::dsl as BlobSchema; 621 621 622 622 self.db 623 623 .get() ··· 653 653 654 654 /// Update the takedown status of a blob 655 655 pub async fn update_blob_takedown_status(&self, blob: Cid, takedown: StatusAttr) -> Result<()> { 656 - use crate::schema::pds::blob::dsl as BlobSchema; 656 + use crate::schema::actor_store::blob::dsl as BlobSchema; 657 657 658 658 let takedown_ref: Option<String> = match takedown.applied { 659 659 true => takedown.r#ref.map_or_else(|| Some(now()), Some),
+2 -2
src/actor_store/mod.rs
··· 481 481 482 482 pub async fn destroy(&mut self) -> Result<()> { 483 483 let did: String = self.did.clone(); 484 - use crate::schema::pds::blob::dsl as BlobSchema; 484 + use crate::schema::actor_store::blob::dsl as BlobSchema; 485 485 486 486 let blob_rows: Vec<String> = self 487 487 .storage ··· 520 520 return Ok(vec![]); 521 521 } 522 522 let did: String = self.did.clone(); 523 - use crate::schema::pds::record::dsl as RecordSchema; 523 + use crate::schema::actor_store::record::dsl as RecordSchema; 524 524 525 525 let cid_strs: Vec<String> = cids.into_iter().map(|c| c.to_string()).collect(); 526 526 let touched_uri_strs: Vec<String> = touched_uris.iter().map(|t| t.to_string()).collect();
+3 -3
src/actor_store/preference.rs
··· 4 4 //! 5 5 //! Modified for SQLite backend 6 6 7 - use crate::models::pds::AccountPref; 7 + use crate::models::actor_store::AccountPref; 8 8 use anyhow::{Result, bail}; 9 9 use diesel::*; 10 10 use rsky_lexicon::app::bsky::actor::RefPreferences; ··· 36 36 namespace: Option<String>, 37 37 scope: AuthScope, 38 38 ) -> Result<Vec<RefPreferences>> { 39 - use crate::schema::pds::account_pref::dsl as AccountPrefSchema; 39 + use crate::schema::actor_store::account_pref::dsl as AccountPrefSchema; 40 40 41 41 let did = self.did.clone(); 42 42 self.db ··· 99 99 bail!("Do not have authorization to set preferences."); 100 100 } 101 101 // get all current prefs for user and prep new pref rows 102 - use crate::schema::pds::account_pref::dsl as AccountPrefSchema; 102 + use crate::schema::actor_store::account_pref::dsl as AccountPrefSchema; 103 103 let all_prefs = AccountPrefSchema::account_pref 104 104 .filter(AccountPrefSchema::did.eq(&did)) 105 105 .select(AccountPref::as_select())
+18 -18
src/actor_store/record.rs
··· 4 4 //! 5 5 //! Modified for SQLite backend 6 6 7 - use crate::models::pds::{Backlink, Record, RepoBlock}; 7 + use crate::models::actor_store::{Backlink, Record, RepoBlock}; 8 8 use anyhow::{Result, bail}; 9 9 use cidv10::Cid; 10 10 use diesel::result::Error; ··· 90 90 91 91 /// Count the total number of records. 92 92 pub(crate) async fn record_count(&mut self) -> Result<i64> { 93 - use crate::schema::pds::record::dsl::*; 93 + use crate::schema::actor_store::record::dsl::*; 94 94 95 95 let other_did = self.did.clone(); 96 96 self.db ··· 106 106 107 107 /// List all collections in the repository. 108 108 pub(crate) async fn list_collections(&self) -> Result<Vec<String>> { 109 - use crate::schema::pds::record::dsl::*; 109 + use crate::schema::actor_store::record::dsl::*; 110 110 111 111 let other_did = self.did.clone(); 112 112 self.db ··· 137 137 rkey_end: Option<String>, 138 138 include_soft_deleted: Option<bool>, 139 139 ) -> Result<Vec<RecordsForCollection>> { 140 - use crate::schema::pds::record::dsl as RecordSchema; 141 - use crate::schema::pds::repo_block::dsl as RepoBlockSchema; 140 + use crate::schema::actor_store::record::dsl as RecordSchema; 141 + use crate::schema::actor_store::repo_block::dsl as RepoBlockSchema; 142 142 143 143 let include_soft_deleted: bool = include_soft_deleted.unwrap_or(false); 144 144 let mut builder = RecordSchema::record ··· 196 196 cid: Option<String>, 197 197 include_soft_deleted: Option<bool>, 198 198 ) -> Result<Option<GetRecord>> { 199 - use crate::schema::pds::record::dsl as RecordSchema; 200 - use crate::schema::pds::repo_block::dsl as RepoBlockSchema; 199 + use crate::schema::actor_store::record::dsl as RecordSchema; 200 + use crate::schema::actor_store::repo_block::dsl as RepoBlockSchema; 201 201 202 202 let include_soft_deleted: bool = include_soft_deleted.unwrap_or(false); 203 203 let mut builder = RecordSchema::record ··· 238 238 cid: Option<String>, 239 239 include_soft_deleted: Option<bool>, 240 240 ) -> Result<bool> { 241 - use crate::schema::pds::record::dsl as RecordSchema; 241 + use crate::schema::actor_store::record::dsl as RecordSchema; 242 242 243 243 let include_soft_deleted: bool = include_soft_deleted.unwrap_or(false); 244 244 let mut builder = RecordSchema::record ··· 266 266 &self, 267 267 uri: String, 268 268 ) -> Result<Option<StatusAttr>> { 269 - use crate::schema::pds::record::dsl as RecordSchema; 269 + use crate::schema::actor_store::record::dsl as RecordSchema; 270 270 271 271 let res = self 272 272 .db ··· 304 304 305 305 /// Get the current CID for a record URI. 306 306 pub(crate) async fn get_current_record_cid(&self, uri: String) -> Result<Option<Cid>> { 307 - use crate::schema::pds::record::dsl as RecordSchema; 307 + use crate::schema::actor_store::record::dsl as RecordSchema; 308 308 309 309 let res = self 310 310 .db ··· 333 333 path: String, 334 334 link_to: String, 335 335 ) -> Result<Vec<Record>> { 336 - use crate::schema::pds::backlink::dsl as BacklinkSchema; 337 - use crate::schema::pds::record::dsl as RecordSchema; 336 + use crate::schema::actor_store::backlink::dsl as BacklinkSchema; 337 + use crate::schema::actor_store::record::dsl as RecordSchema; 338 338 339 339 let res = self 340 340 .db ··· 432 432 bail!("Expected indexed URI to contain a record key") 433 433 } 434 434 435 - use crate::schema::pds::record::dsl as RecordSchema; 435 + use crate::schema::actor_store::record::dsl as RecordSchema; 436 436 437 437 // Track current version of record 438 438 let (record, uri) = self ··· 473 473 #[tracing::instrument(skip_all)] 474 474 pub(crate) async fn delete_record(&self, uri: &AtUri) -> Result<()> { 475 475 tracing::debug!("@LOG DEBUG RecordReader::delete_record, deleting indexed record {uri}"); 476 - use crate::schema::pds::backlink::dsl as BacklinkSchema; 477 - use crate::schema::pds::record::dsl as RecordSchema; 476 + use crate::schema::actor_store::backlink::dsl as BacklinkSchema; 477 + use crate::schema::actor_store::record::dsl as RecordSchema; 478 478 let uri = uri.to_string(); 479 479 self.db 480 480 .get() ··· 497 497 498 498 /// Remove backlinks for a URI. 499 499 pub(crate) async fn remove_backlinks_by_uri(&self, uri: &AtUri) -> Result<()> { 500 - use crate::schema::pds::backlink::dsl as BacklinkSchema; 500 + use crate::schema::actor_store::backlink::dsl as BacklinkSchema; 501 501 let uri = uri.to_string(); 502 502 self.db 503 503 .get() ··· 517 517 if backlinks.is_empty() { 518 518 Ok(()) 519 519 } else { 520 - use crate::schema::pds::backlink::dsl as BacklinkSchema; 520 + use crate::schema::actor_store::backlink::dsl as BacklinkSchema; 521 521 self.db 522 522 .get() 523 523 .await? ··· 538 538 uri: &AtUri, 539 539 takedown: StatusAttr, 540 540 ) -> Result<()> { 541 - use crate::schema::pds::record::dsl as RecordSchema; 541 + use crate::schema::actor_store::record::dsl as RecordSchema; 542 542 543 543 let takedown_ref: Option<String> = match takedown.applied { 544 544 true => takedown
+12 -12
src/actor_store/sql_repo.rs
··· 3 3 //! 4 4 //! Modified for SQLite backend 5 5 6 - use crate::models::pds as models; 7 - use crate::models::pds::RepoBlock; 6 + use crate::models::actor_store as models; 7 + use crate::models::actor_store::RepoBlock; 8 8 use anyhow::Result; 9 9 use cidv10::Cid; 10 10 use diesel::dsl::sql; ··· 53 53 let cid = *cid; 54 54 55 55 Box::pin(async move { 56 - use crate::schema::pds::repo_block::dsl as RepoBlockSchema; 56 + use crate::schema::actor_store::repo_block::dsl as RepoBlockSchema; 57 57 let cached = { 58 58 let cache_guard = self.cache.read().await; 59 59 cache_guard.get(cid).cloned() ··· 104 104 let did: String = self.did.clone(); 105 105 106 106 Box::pin(async move { 107 - use crate::schema::pds::repo_block::dsl as RepoBlockSchema; 107 + use crate::schema::actor_store::repo_block::dsl as RepoBlockSchema; 108 108 let cached = { 109 109 let mut cache_guard = self.cache.write().await; 110 110 cache_guard.get_many(cids)? ··· 202 202 let did: String = self.did.clone(); 203 203 let bytes_cloned = bytes.clone(); 204 204 Box::pin(async move { 205 - use crate::schema::pds::repo_block::dsl as RepoBlockSchema; 205 + use crate::schema::actor_store::repo_block::dsl as RepoBlockSchema; 206 206 207 207 _ = self 208 208 .db ··· 235 235 let did: String = self.did.clone(); 236 236 237 237 Box::pin(async move { 238 - use crate::schema::pds::repo_block::dsl as RepoBlockSchema; 238 + use crate::schema::actor_store::repo_block::dsl as RepoBlockSchema; 239 239 240 240 let blocks: Vec<RepoBlock> = to_put 241 241 .map ··· 277 277 let now: String = self.now.clone(); 278 278 279 279 Box::pin(async move { 280 - use crate::schema::pds::repo_root::dsl as RepoRootSchema; 280 + use crate::schema::actor_store::repo_root::dsl as RepoRootSchema; 281 281 282 282 let is_create = is_create.unwrap_or(false); 283 283 if is_create { ··· 381 381 let did: String = self.did.clone(); 382 382 let since = since.clone(); 383 383 let cursor = cursor.clone(); 384 - use crate::schema::pds::repo_block::dsl as RepoBlockSchema; 384 + use crate::schema::actor_store::repo_block::dsl as RepoBlockSchema; 385 385 386 386 Ok(self 387 387 .db ··· 418 418 419 419 pub async fn count_blocks(&self) -> Result<i64> { 420 420 let did: String = self.did.clone(); 421 - use crate::schema::pds::repo_block::dsl as RepoBlockSchema; 421 + use crate::schema::actor_store::repo_block::dsl as RepoBlockSchema; 422 422 423 423 let res = self 424 424 .db ··· 439 439 /// Proactively cache all blocks from a particular commit (to prevent multiple roundtrips) 440 440 pub async fn cache_rev(&mut self, rev: String) -> Result<()> { 441 441 let did: String = self.did.clone(); 442 - use crate::schema::pds::repo_block::dsl as RepoBlockSchema; 442 + use crate::schema::actor_store::repo_block::dsl as RepoBlockSchema; 443 443 444 444 let result: Vec<(String, Vec<u8>)> = self 445 445 .db ··· 465 465 return Ok(()); 466 466 } 467 467 let did: String = self.did.clone(); 468 - use crate::schema::pds::repo_block::dsl as RepoBlockSchema; 468 + use crate::schema::actor_store::repo_block::dsl as RepoBlockSchema; 469 469 470 470 let cid_strings: Vec<String> = cids.into_iter().map(|c| c.to_string()).collect(); 471 471 _ = self ··· 483 483 484 484 pub async fn get_root_detailed(&self) -> Result<CidAndRev> { 485 485 let did: String = self.did.clone(); 486 - use crate::schema::pds::repo_root::dsl as RepoRootSchema; 486 + use crate::schema::actor_store::repo_root::dsl as RepoRootSchema; 487 487 488 488 let res = self 489 489 .db
+1
src/apis/com/atproto/repo/apply_writes.rs
··· 134 134 did.to_string(), 135 135 commit.commit_data.cid, 136 136 commit.commit_data.rev, 137 + &actor_pools, 137 138 ) 138 139 .await?; 139 140 Ok(())
+204 -188
src/models.rs
··· 156 156 #[derive( 157 157 Queryable, 158 158 Identifiable, 159 - Insertable, 160 - Selectable, 161 - Clone, 162 - Debug, 163 - PartialEq, 164 - Default, 165 - Serialize, 166 - Deserialize, 167 - )] 168 - #[diesel(table_name = crate::schema::pds::account_pref)] 169 - #[diesel(check_for_backend(Sqlite))] 170 - pub struct AccountPref { 171 - pub id: i32, 172 - pub name: String, 173 - #[diesel(column_name = valueJson)] 174 - #[serde(rename = "valueJson")] 175 - pub value_json: Option<String>, 176 - } 177 - 178 - #[derive( 179 - Queryable, 180 - Identifiable, 181 159 Selectable, 182 160 Clone, 183 161 Debug, ··· 227 205 #[diesel(column_name = createdAt)] 228 206 #[serde(rename = "createdAt")] 229 207 pub created_at: String, 230 - } 231 - 232 - #[derive( 233 - Queryable, 234 - Identifiable, 235 - Insertable, 236 - Selectable, 237 - Clone, 238 - Debug, 239 - PartialEq, 240 - Default, 241 - Serialize, 242 - Deserialize, 243 - )] 244 - #[diesel(primary_key(uri, path))] 245 - #[diesel(table_name = crate::schema::pds::backlink)] 246 - #[diesel(check_for_backend(Sqlite))] 247 - pub struct Backlink { 248 - pub uri: String, 249 - pub path: String, 250 - #[diesel(column_name = linkTo)] 251 - #[serde(rename = "linkTo")] 252 - pub link_to: String, 253 - } 254 - 255 - #[derive( 256 - Queryable, 257 - Identifiable, 258 - Selectable, 259 - Clone, 260 - Debug, 261 - PartialEq, 262 - Default, 263 - Serialize, 264 - Deserialize, 265 - )] 266 - #[diesel(treat_none_as_null = true)] 267 - #[diesel(primary_key(cid))] 268 - #[diesel(table_name = crate::schema::pds::blob)] 269 - #[diesel(check_for_backend(Sqlite))] 270 - pub struct Blob { 271 - pub cid: String, 272 - pub did: String, 273 - #[diesel(column_name = mimeType)] 274 - #[serde(rename = "mimeType")] 275 - pub mime_type: String, 276 - pub size: i32, 277 - #[diesel(column_name = tempKey)] 278 - #[serde(rename = "tempKey")] 279 - pub temp_key: Option<String>, 280 - pub width: Option<i32>, 281 - pub height: Option<i32>, 282 - #[diesel(column_name = createdAt)] 283 - #[serde(rename = "createdAt")] 284 - pub created_at: String, 285 - #[diesel(column_name = takedownRef)] 286 - #[serde(rename = "takedownRef")] 287 - pub takedown_ref: Option<String>, 288 208 } 289 209 290 210 #[derive( ··· 460 380 #[derive( 461 381 Queryable, 462 382 Identifiable, 463 - Insertable, 464 - Selectable, 465 - Clone, 466 - Debug, 467 - PartialEq, 468 - Default, 469 - Serialize, 470 - Deserialize, 471 - )] 472 - #[diesel(primary_key(uri))] 473 - #[diesel(table_name = crate::schema::pds::record)] 474 - #[diesel(check_for_backend(Sqlite))] 475 - pub struct Record { 476 - pub uri: String, 477 - pub cid: String, 478 - pub did: String, 479 - pub collection: String, 480 - pub rkey: String, 481 - #[diesel(column_name = repoRev)] 482 - #[serde(rename = "repoRev")] 483 - pub repo_rev: Option<String>, 484 - #[diesel(column_name = indexedAt)] 485 - #[serde(rename = "indexedAt")] 486 - pub indexed_at: String, 487 - #[diesel(column_name = takedownRef)] 488 - #[serde(rename = "takedownRef")] 489 - pub takedown_ref: Option<String>, 490 - } 491 - 492 - #[derive( 493 - QueryableByName, 494 - Queryable, 495 - Identifiable, 496 - Selectable, 497 - Clone, 498 - Debug, 499 - PartialEq, 500 - Default, 501 - Serialize, 502 - Deserialize, 503 - )] 504 - #[diesel(primary_key(blobCid, recordUri))] 505 - #[diesel(table_name = crate::schema::pds::record_blob)] 506 - #[diesel(check_for_backend(Sqlite))] 507 - pub struct RecordBlob { 508 - #[diesel(column_name = blobCid, sql_type = Text)] 509 - #[serde(rename = "blobCid")] 510 - pub blob_cid: String, 511 - #[diesel(column_name = recordUri, sql_type = Text)] 512 - #[serde(rename = "recordUri")] 513 - pub record_uri: String, 514 - #[diesel(sql_type = Text)] 515 - pub did: String, 516 - } 517 - 518 - #[derive( 519 - Queryable, 520 - Identifiable, 521 383 Selectable, 522 384 Clone, 523 385 Debug, ··· 540 402 #[diesel(column_name = appPasswordName)] 541 403 #[serde(rename = "appPasswordName")] 542 404 pub app_password_name: Option<String>, 543 - } 544 - 545 - #[derive( 546 - Queryable, 547 - Identifiable, 548 - Selectable, 549 - Insertable, 550 - Clone, 551 - Debug, 552 - PartialEq, 553 - Default, 554 - Serialize, 555 - Deserialize, 556 - )] 557 - #[diesel(primary_key(cid))] 558 - #[diesel(table_name = crate::schema::pds::repo_block)] 559 - #[diesel(check_for_backend(Sqlite))] 560 - pub struct RepoBlock { 561 - #[diesel(sql_type = Text)] 562 - pub cid: String, 563 - pub did: String, 564 - #[diesel(column_name = repoRev)] 565 - #[serde(rename = "repoRev")] 566 - pub repo_rev: String, 567 - pub size: i32, 568 - #[diesel(sql_type = Bytea)] 569 - pub content: Vec<u8>, 570 - } 571 - 572 - #[derive( 573 - Queryable, 574 - Identifiable, 575 - Selectable, 576 - Clone, 577 - Debug, 578 - PartialEq, 579 - Default, 580 - Serialize, 581 - Deserialize, 582 - )] 583 - #[diesel(primary_key(did))] 584 - #[diesel(table_name = crate::schema::pds::repo_root)] 585 - #[diesel(check_for_backend(Sqlite))] 586 - pub struct RepoRoot { 587 - pub did: String, 588 - pub cid: String, 589 - pub rev: String, 590 - #[diesel(column_name = indexedAt)] 591 - #[serde(rename = "indexedAt")] 592 - pub indexed_at: String, 593 405 } 594 406 595 407 #[derive( ··· 791 603 pub refresh_token: String, 792 604 } 793 605 } 606 + 607 + pub mod actor_store { 608 + 609 + #![allow(unnameable_types, unused_qualifications)] 610 + use anyhow::{Result, bail}; 611 + use chrono::DateTime; 612 + use chrono::offset::Utc; 613 + use diesel::backend::Backend; 614 + use diesel::deserialize::FromSql; 615 + use diesel::prelude::*; 616 + use diesel::serialize::{Output, ToSql}; 617 + use diesel::sql_types::Text; 618 + use diesel::sqlite::Sqlite; 619 + use diesel::*; 620 + use serde::{Deserialize, Serialize}; 621 + 622 + #[derive( 623 + Queryable, 624 + Identifiable, 625 + Insertable, 626 + Selectable, 627 + Clone, 628 + Debug, 629 + PartialEq, 630 + Default, 631 + Serialize, 632 + Deserialize, 633 + )] 634 + #[diesel(table_name = crate::schema::actor_store::account_pref)] 635 + #[diesel(check_for_backend(Sqlite))] 636 + pub struct AccountPref { 637 + pub id: i32, 638 + pub name: String, 639 + #[diesel(column_name = valueJson)] 640 + #[serde(rename = "valueJson")] 641 + pub value_json: Option<String>, 642 + } 643 + 644 + #[derive( 645 + Queryable, 646 + Identifiable, 647 + Insertable, 648 + Selectable, 649 + Clone, 650 + Debug, 651 + PartialEq, 652 + Default, 653 + Serialize, 654 + Deserialize, 655 + )] 656 + #[diesel(primary_key(uri, path))] 657 + #[diesel(table_name = crate::schema::actor_store::backlink)] 658 + #[diesel(check_for_backend(Sqlite))] 659 + pub struct Backlink { 660 + pub uri: String, 661 + pub path: String, 662 + #[diesel(column_name = linkTo)] 663 + #[serde(rename = "linkTo")] 664 + pub link_to: String, 665 + } 666 + 667 + #[derive( 668 + Queryable, 669 + Identifiable, 670 + Selectable, 671 + Clone, 672 + Debug, 673 + PartialEq, 674 + Default, 675 + Serialize, 676 + Deserialize, 677 + )] 678 + #[diesel(treat_none_as_null = true)] 679 + #[diesel(primary_key(cid))] 680 + #[diesel(table_name = crate::schema::actor_store::blob)] 681 + #[diesel(check_for_backend(Sqlite))] 682 + pub struct Blob { 683 + pub cid: String, 684 + pub did: String, 685 + #[diesel(column_name = mimeType)] 686 + #[serde(rename = "mimeType")] 687 + pub mime_type: String, 688 + pub size: i32, 689 + #[diesel(column_name = tempKey)] 690 + #[serde(rename = "tempKey")] 691 + pub temp_key: Option<String>, 692 + pub width: Option<i32>, 693 + pub height: Option<i32>, 694 + #[diesel(column_name = createdAt)] 695 + #[serde(rename = "createdAt")] 696 + pub created_at: String, 697 + #[diesel(column_name = takedownRef)] 698 + #[serde(rename = "takedownRef")] 699 + pub takedown_ref: Option<String>, 700 + } 701 + 702 + #[derive( 703 + Queryable, 704 + Identifiable, 705 + Insertable, 706 + Selectable, 707 + Clone, 708 + Debug, 709 + PartialEq, 710 + Default, 711 + Serialize, 712 + Deserialize, 713 + )] 714 + #[diesel(primary_key(uri))] 715 + #[diesel(table_name = crate::schema::actor_store::record)] 716 + #[diesel(check_for_backend(Sqlite))] 717 + pub struct Record { 718 + pub uri: String, 719 + pub cid: String, 720 + pub did: String, 721 + pub collection: String, 722 + pub rkey: String, 723 + #[diesel(column_name = repoRev)] 724 + #[serde(rename = "repoRev")] 725 + pub repo_rev: Option<String>, 726 + #[diesel(column_name = indexedAt)] 727 + #[serde(rename = "indexedAt")] 728 + pub indexed_at: String, 729 + #[diesel(column_name = takedownRef)] 730 + #[serde(rename = "takedownRef")] 731 + pub takedown_ref: Option<String>, 732 + } 733 + 734 + #[derive( 735 + QueryableByName, 736 + Queryable, 737 + Identifiable, 738 + Selectable, 739 + Clone, 740 + Debug, 741 + PartialEq, 742 + Default, 743 + Serialize, 744 + Deserialize, 745 + )] 746 + #[diesel(primary_key(blobCid, recordUri))] 747 + #[diesel(table_name = crate::schema::actor_store::record_blob)] 748 + #[diesel(check_for_backend(Sqlite))] 749 + pub struct RecordBlob { 750 + #[diesel(column_name = blobCid, sql_type = Text)] 751 + #[serde(rename = "blobCid")] 752 + pub blob_cid: String, 753 + #[diesel(column_name = recordUri, sql_type = Text)] 754 + #[serde(rename = "recordUri")] 755 + pub record_uri: String, 756 + #[diesel(sql_type = Text)] 757 + pub did: String, 758 + } 759 + 760 + #[derive( 761 + Queryable, 762 + Identifiable, 763 + Selectable, 764 + Insertable, 765 + Clone, 766 + Debug, 767 + PartialEq, 768 + Default, 769 + Serialize, 770 + Deserialize, 771 + )] 772 + #[diesel(primary_key(cid))] 773 + #[diesel(table_name = crate::schema::actor_store::repo_block)] 774 + #[diesel(check_for_backend(Sqlite))] 775 + pub struct RepoBlock { 776 + #[diesel(sql_type = Text)] 777 + pub cid: String, 778 + pub did: String, 779 + #[diesel(column_name = repoRev)] 780 + #[serde(rename = "repoRev")] 781 + pub repo_rev: String, 782 + pub size: i32, 783 + #[diesel(sql_type = Bytea)] 784 + pub content: Vec<u8>, 785 + } 786 + 787 + #[derive( 788 + Queryable, 789 + Identifiable, 790 + Selectable, 791 + Clone, 792 + Debug, 793 + PartialEq, 794 + Default, 795 + Serialize, 796 + Deserialize, 797 + )] 798 + #[diesel(primary_key(did))] 799 + #[diesel(table_name = crate::schema::actor_store::repo_root)] 800 + #[diesel(check_for_backend(Sqlite))] 801 + pub struct RepoRoot { 802 + pub did: String, 803 + pub cid: String, 804 + pub rev: String, 805 + #[diesel(column_name = indexedAt)] 806 + #[serde(rename = "indexedAt")] 807 + pub indexed_at: String, 808 + } 809 + }
+90 -78
src/schema.rs
··· 70 70 } 71 71 72 72 diesel::table! { 73 - account_pref (id) { 74 - id -> Int4, 75 - did -> Varchar, 76 - name -> Varchar, 77 - valueJson -> Nullable<Text>, 78 - } 79 - } 80 - 81 - diesel::table! { 82 73 actor (did) { 83 74 did -> Varchar, 84 75 handle -> Nullable<Varchar>, ··· 112 103 } 113 104 114 105 diesel::table! { 115 - backlink (uri, path) { 116 - uri -> Varchar, 117 - path -> Varchar, 118 - linkTo -> Varchar, 119 - } 120 - } 121 - 122 - diesel::table! { 123 - blob (cid, did) { 124 - cid -> Varchar, 125 - did -> Varchar, 126 - mimeType -> Varchar, 127 - size -> Int4, 128 - tempKey -> Nullable<Varchar>, 129 - width -> Nullable<Int4>, 130 - height -> Nullable<Int4>, 131 - createdAt -> Varchar, 132 - takedownRef -> Nullable<Varchar>, 133 - } 134 - } 135 - 136 - diesel::table! { 137 106 device (id) { 138 107 id -> Varchar, 139 108 sessionId -> Nullable<Varchar>, ··· 190 159 } 191 160 192 161 diesel::table! { 193 - record (uri) { 194 - uri -> Varchar, 195 - cid -> Varchar, 196 - did -> Varchar, 197 - collection -> Varchar, 198 - rkey -> Varchar, 199 - repoRev -> Nullable<Varchar>, 200 - indexedAt -> Varchar, 201 - takedownRef -> Nullable<Varchar>, 202 - } 203 - } 204 - 205 - diesel::table! { 206 - record_blob (blobCid, recordUri) { 207 - blobCid -> Varchar, 208 - recordUri -> Varchar, 209 - did -> Varchar, 210 - } 211 - } 212 - 213 - diesel::table! { 214 162 refresh_token (id) { 215 163 id -> Varchar, 216 164 did -> Varchar, ··· 221 169 } 222 170 223 171 diesel::table! { 224 - repo_block (cid, did) { 225 - cid -> Varchar, 226 - did -> Varchar, 227 - repoRev -> Varchar, 228 - size -> Int4, 229 - content -> Bytea, 230 - } 231 - } 232 - 233 - diesel::table! { 234 - repo_root (did) { 235 - did -> Varchar, 236 - cid -> Varchar, 237 - rev -> Varchar, 238 - indexedAt -> Varchar, 239 - } 240 - } 241 - 242 - diesel::table! { 243 172 repo_seq (seq) { 244 173 seq -> Int8, 245 174 did -> Varchar, ··· 277 206 278 207 diesel::allow_tables_to_appear_in_same_query!( 279 208 account, 280 - account_pref, 281 209 actor, 282 210 app_password, 283 211 authorization_request, 284 - backlink, 285 - blob, 286 212 device, 287 213 device_account, 288 214 did_doc, 289 215 email_token, 290 216 invite_code, 291 217 invite_code_use, 292 - record, 293 - record_blob, 294 218 refresh_token, 295 - repo_block, 296 - repo_root, 297 219 repo_seq, 298 220 token, 299 221 used_refresh_token, 300 222 ); 301 223 } 224 + 225 + pub mod actor_store { 226 + // Actor Store 227 + 228 + // Blob 229 + diesel::table! { 230 + blob (cid, did) { 231 + cid -> Varchar, 232 + did -> Varchar, 233 + mimeType -> Varchar, 234 + size -> Int4, 235 + tempKey -> Nullable<Varchar>, 236 + width -> Nullable<Int4>, 237 + height -> Nullable<Int4>, 238 + createdAt -> Varchar, 239 + takedownRef -> Nullable<Varchar>, 240 + } 241 + } 242 + 243 + diesel::table! { 244 + record_blob (blobCid, recordUri) { 245 + blobCid -> Varchar, 246 + recordUri -> Varchar, 247 + did -> Varchar, 248 + } 249 + } 250 + 251 + // Preference 252 + 253 + diesel::table! { 254 + account_pref (id) { 255 + id -> Int4, 256 + did -> Varchar, 257 + name -> Varchar, 258 + valueJson -> Nullable<Text>, 259 + } 260 + } 261 + // Record 262 + 263 + diesel::table! { 264 + record (uri) { 265 + uri -> Varchar, 266 + cid -> Varchar, 267 + did -> Varchar, 268 + collection -> Varchar, 269 + rkey -> Varchar, 270 + repoRev -> Nullable<Varchar>, 271 + indexedAt -> Varchar, 272 + takedownRef -> Nullable<Varchar>, 273 + } 274 + } 275 + 276 + diesel::table! { 277 + repo_block (cid, did) { 278 + cid -> Varchar, 279 + did -> Varchar, 280 + repoRev -> Varchar, 281 + size -> Int4, 282 + content -> Bytea, 283 + } 284 + } 285 + 286 + diesel::table! { 287 + backlink (uri, path) { 288 + uri -> Varchar, 289 + path -> Varchar, 290 + linkTo -> Varchar, 291 + } 292 + } 293 + // sql_repo 294 + 295 + diesel::table! { 296 + repo_root (did) { 297 + did -> Varchar, 298 + cid -> Varchar, 299 + rev -> Varchar, 300 + indexedAt -> Varchar, 301 + } 302 + } 303 + 304 + diesel::allow_tables_to_appear_in_same_query!( 305 + account_pref, 306 + backlink, 307 + blob, 308 + record, 309 + record_blob, 310 + repo_block, 311 + repo_root, 312 + ); 313 + }