diff --git a/Cargo.lock b/Cargo.lock index 5083b91312..7b09775f2a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" + [[package]] name = "activity_indicator" version = "0.1.0" @@ -107,6 +113,12 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "aliasable" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" + [[package]] name = "ambient-authority" version = "0.0.1" @@ -547,6 +559,19 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "bae" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b8de67cc41132507eeece2584804efcb15f85ba516e34c944b7667f480397a" +dependencies = [ + "heck 0.3.3", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "base64" version = "0.13.0" @@ -635,6 +660,51 @@ dependencies = [ "once_cell", ] +[[package]] +name = "borsh" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" +dependencies = [ + "borsh-derive", + "hashbrown 0.11.2", +] + +[[package]] +name = "borsh-derive" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" +dependencies = [ + "borsh-derive-internal", + "borsh-schema-derive-internal", + "proc-macro-crate", + "proc-macro2", + "syn", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "breadcrumbs" version = "0.1.0" @@ -678,6 +748,27 @@ version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" +[[package]] +name = "bytecheck" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d11cac2c12b5adc6570dad2ee1b87eff4955dac476fe12d81e5fdd352e52406f" +dependencies = [ + "bytecheck_derive", + "ptr_meta", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13e576ebe98e605500b3c8041bb888e966653577172df6dd97398714eb30b9bf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "bytemuck" version = "1.12.1" @@ -841,6 +932,7 @@ dependencies = [ "js-sys", "num-integer", "num-traits", + "serde", "time 0.1.44", "wasm-bindgen", "winapi 0.3.9", @@ -1065,6 +1157,7 @@ dependencies = [ "reqwest", "rpc", "scrypt", + "sea-orm", "sea-query", "sea-query-binder", "serde", @@ -3843,6 +3936,29 @@ version = "6.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" +[[package]] +name = "ouroboros" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbb50b356159620db6ac971c6d5c9ab788c9cc38a6f49619fca2a27acb062ca" +dependencies = [ + "aliasable", + "ouroboros_macro", +] + +[[package]] +name = "ouroboros_macro" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0d9d1a6191c4f391f87219d1ea42b23f09ee84d64763cd05ee6ea88d9f384d" +dependencies = [ + "Inflector", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "outline" version = "0.1.0" @@ -4201,6 +4317,15 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -4446,6 +4571,26 @@ dependencies = [ "cc", ] +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "pulldown-cmark" version = "0.9.2" @@ -4683,6 +4828,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "rend" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79af64b4b6362ffba04eef3a4e10829718a4896dac19daa741851c86781edf95" +dependencies = [ + "bytecheck", +] + [[package]] name = "reqwest" version = "0.11.12" @@ -4760,6 +4914,31 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "rkyv" +version = "0.7.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cec2b3485b07d96ddfd3134767b8a447b45ea4eb91448d0a35180ec0ffd5ed15" +dependencies = [ + "bytecheck", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eaedadc88b53e36dd32d940ed21ae4d850d5916f2581526921f553a72ac34c4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "rmp" version = "0.8.11" @@ -4911,6 +5090,24 @@ dependencies = [ "walkdir", ] +[[package]] +name = "rust_decimal" +version = "1.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c321ee4e17d2b7abe12b5d20c1231db708dd36185c8a21e9de5fed6da4dbe9" +dependencies = [ + "arrayvec 0.7.2", + "borsh", + "bytecheck", + "byteorder", + "bytes 1.2.1", + "num-traits", + "rand 0.8.5", + "rkyv", + "serde", + "serde_json", +] + [[package]] name = "rustc-demangle" version = "0.1.21" @@ -4982,6 +5179,12 @@ dependencies = [ "base64", ] +[[package]] +name = "rustversion" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" + [[package]] name = "rustybuzz" version = "0.3.0" @@ -5123,13 +5326,59 @@ dependencies = [ "untrusted", ] +[[package]] +name = "sea-orm" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3120bc435b8640963ffda698f877610e07e077157e216eb99408d819c344034d" +dependencies = [ + "async-stream", + "async-trait", + "chrono", + "futures 0.3.24", + "futures-util", + "log", + "ouroboros", + "rust_decimal", + "sea-orm-macros", + "sea-query", + "sea-query-binder", + "sea-strum", + "serde", + "serde_json", + "sqlx", + "thiserror", + "time 0.3.15", + "tracing", + "url", + "uuid 1.2.1", +] + +[[package]] +name = "sea-orm-macros" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c54bacfeb842813c16821e21f9456c358861a448294075184ea1d6307e386d08" +dependencies = [ + "bae", + "heck 0.3.3", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sea-query" version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4f0fc4d8e44e1d51c739a68d336252a18bc59553778075d5e32649be6ec92ed" dependencies = [ + "chrono", + "rust_decimal", "sea-query-derive", + "serde_json", + "time 0.3.15", + "uuid 1.2.1", ] [[package]] @@ -5138,8 +5387,13 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c2585b89c985cfacfe0ec9fc9e7bb055b776c1a2581c4e3c6185af2b8bf8865" dependencies = [ + "chrono", + "rust_decimal", "sea-query", + "serde_json", "sqlx", + "time 0.3.15", + "uuid 1.2.1", ] [[package]] @@ -5155,6 +5409,28 @@ dependencies = [ "thiserror", ] +[[package]] +name = "sea-strum" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "391d06a6007842cfe79ac6f7f53911b76dfd69fc9a6769f1cf6569d12ce20e1b" +dependencies = [ + "sea-strum_macros", +] + +[[package]] +name = "sea-strum_macros" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69b4397b825df6ccf1e98bcdabef3bbcfc47ff5853983467850eeab878384f21" +dependencies = [ + "heck 0.3.3", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + [[package]] name = "seahash" version = "4.1.0" @@ -5670,6 +5946,7 @@ dependencies = [ "bitflags", "byteorder", "bytes 1.2.1", + "chrono", "crc", "crossbeam-queue", "dirs 4.0.0", @@ -5693,10 +5970,12 @@ dependencies = [ "log", "md-5", "memchr", + "num-bigint", "once_cell", "paste", "percent-encoding", "rand 0.8.5", + "rust_decimal", "rustls 0.20.7", "rustls-pemfile", "serde", @@ -6847,6 +7126,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "feb41e78f93363bb2df8b0e86a2ca30eed7806ea16ea0c790d757cf93f79be83" dependencies = [ "getrandom 0.2.7", + "serde", ] [[package]] diff --git a/crates/collab/Cargo.toml b/crates/collab/Cargo.toml index e854b003c8..e10f9fe8dc 100644 --- a/crates/collab/Cargo.toml +++ b/crates/collab/Cargo.toml @@ -36,6 +36,7 @@ prometheus = "0.13" rand = "0.8" reqwest = { version = "0.11", features = ["json"], optional = true } scrypt = "0.7" +sea-orm = { version = "0.10", features = ["sqlx-postgres", "runtime-tokio-rustls"] } sea-query = { version = "0.27", features = ["derive"] } sea-query-binder = { version = "0.2", features = ["sqlx-postgres"] } serde = { version = "1.0", features = ["derive", "rc"] } @@ -74,6 +75,7 @@ env_logger = "0.9" log = { version = "0.4.16", features = ["kv_unstable_serde"] } util = { path = "../util" } lazy_static = "1.4" +sea-orm = { version = "0.10", features = ["sqlx-sqlite"] } sea-query-binder = { version = "0.2", features = ["sqlx-sqlite"] } serde_json = { version = "1.0", features = ["preserve_order"] } sqlx = { version = "0.6", features = ["sqlite"] } diff --git a/crates/collab/migrations.sqlite/20221109000000_test_schema.sql b/crates/collab/migrations.sqlite/20221109000000_test_schema.sql index 02ca0c75a9..65bf00e74c 100644 --- a/crates/collab/migrations.sqlite/20221109000000_test_schema.sql +++ b/crates/collab/migrations.sqlite/20221109000000_test_schema.sql @@ -41,7 +41,7 @@ CREATE TABLE "rooms" ( CREATE TABLE "projects" ( "id" INTEGER PRIMARY KEY, - "room_id" INTEGER REFERENCES rooms (id), + "room_id" INTEGER REFERENCES rooms (id) NOT NULL, "host_user_id" INTEGER REFERENCES users (id) NOT NULL, "host_connection_id" INTEGER NOT NULL ); diff --git a/crates/collab/src/db2.rs b/crates/collab/src/db2.rs new file mode 100644 index 0000000000..687e93daae --- /dev/null +++ b/crates/collab/src/db2.rs @@ -0,0 +1,316 @@ +mod project; +mod project_collaborator; +mod room; +mod room_participant; +mod worktree; + +use crate::{Error, Result}; +use anyhow::anyhow; +use collections::HashMap; +use dashmap::DashMap; +use futures::StreamExt; +use rpc::{proto, ConnectionId}; +use sea_orm::ActiveValue; +use sea_orm::{ + entity::prelude::*, ConnectOptions, DatabaseConnection, DatabaseTransaction, DbErr, + TransactionTrait, +}; +use serde::{Deserialize, Serialize}; +use std::ops::{Deref, DerefMut}; +use std::{future::Future, marker::PhantomData, rc::Rc, sync::Arc}; +use tokio::sync::{Mutex, OwnedMutexGuard}; + +pub struct Database { + pool: DatabaseConnection, + rooms: DashMap>>, + #[cfg(test)] + background: Option>, + #[cfg(test)] + runtime: Option, +} + +impl Database { + pub async fn new(url: &str, max_connections: u32) -> Result { + let mut options = ConnectOptions::new(url.into()); + options.max_connections(max_connections); + Ok(Self { + pool: sea_orm::Database::connect(options).await?, + rooms: DashMap::with_capacity(16384), + #[cfg(test)] + background: None, + #[cfg(test)] + runtime: None, + }) + } + + pub async fn share_project( + &self, + room_id: RoomId, + connection_id: ConnectionId, + worktrees: &[proto::WorktreeMetadata], + ) -> Result> { + self.transact(|tx| async move { + let participant = room_participant::Entity::find() + .filter(room_participant::Column::AnsweringConnectionId.eq(connection_id.0)) + .one(&tx) + .await? + .ok_or_else(|| anyhow!("could not find participant"))?; + if participant.room_id != room_id.0 { + return Err(anyhow!("shared project on unexpected room"))?; + } + + let project = project::ActiveModel { + room_id: ActiveValue::set(participant.room_id), + host_user_id: ActiveValue::set(participant.user_id), + host_connection_id: ActiveValue::set(connection_id.0 as i32), + ..Default::default() + } + .insert(&tx) + .await?; + + worktree::Entity::insert_many(worktrees.iter().map(|worktree| worktree::ActiveModel { + id: ActiveValue::set(worktree.id as i32), + project_id: ActiveValue::set(project.id), + abs_path: ActiveValue::set(worktree.abs_path.clone()), + root_name: ActiveValue::set(worktree.root_name.clone()), + visible: ActiveValue::set(worktree.visible), + scan_id: ActiveValue::set(0), + is_complete: ActiveValue::set(false), + })) + .exec(&tx) + .await?; + + project_collaborator::ActiveModel { + project_id: ActiveValue::set(project.id), + connection_id: ActiveValue::set(connection_id.0 as i32), + user_id: ActiveValue::set(participant.user_id), + replica_id: ActiveValue::set(0), + is_host: ActiveValue::set(true), + ..Default::default() + } + .insert(&tx) + .await?; + + let room = self.get_room(room_id, &tx).await?; + self.commit_room_transaction(room_id, tx, (ProjectId(project.id), room)) + .await + }) + .await + } + + async fn get_room(&self, room_id: RoomId, tx: &DatabaseTransaction) -> Result { + let db_room = room::Entity::find_by_id(room_id.0) + .one(tx) + .await? + .ok_or_else(|| anyhow!("could not find room"))?; + + let mut db_participants = db_room + .find_related(room_participant::Entity) + .stream(tx) + .await?; + let mut participants = HashMap::default(); + let mut pending_participants = Vec::new(); + while let Some(db_participant) = db_participants.next().await { + let db_participant = db_participant?; + if let Some(answering_connection_id) = db_participant.answering_connection_id { + let location = match ( + db_participant.location_kind, + db_participant.location_project_id, + ) { + (Some(0), Some(project_id)) => { + Some(proto::participant_location::Variant::SharedProject( + proto::participant_location::SharedProject { + id: project_id as u64, + }, + )) + } + (Some(1), _) => Some(proto::participant_location::Variant::UnsharedProject( + Default::default(), + )), + _ => Some(proto::participant_location::Variant::External( + Default::default(), + )), + }; + participants.insert( + answering_connection_id, + proto::Participant { + user_id: db_participant.user_id as u64, + peer_id: answering_connection_id as u32, + projects: Default::default(), + location: Some(proto::ParticipantLocation { variant: location }), + }, + ); + } else { + pending_participants.push(proto::PendingParticipant { + user_id: db_participant.user_id as u64, + calling_user_id: db_participant.calling_user_id as u64, + initial_project_id: db_participant.initial_project_id.map(|id| id as u64), + }); + } + } + + let mut db_projects = db_room + .find_related(project::Entity) + .find_with_related(worktree::Entity) + .stream(tx) + .await?; + + while let Some(row) = db_projects.next().await { + let (db_project, db_worktree) = row?; + if let Some(participant) = participants.get_mut(&db_project.host_connection_id) { + let project = if let Some(project) = participant + .projects + .iter_mut() + .find(|project| project.id as i32 == db_project.id) + { + project + } else { + participant.projects.push(proto::ParticipantProject { + id: db_project.id as u64, + worktree_root_names: Default::default(), + }); + participant.projects.last_mut().unwrap() + }; + + if let Some(db_worktree) = db_worktree { + project.worktree_root_names.push(db_worktree.root_name); + } + } + } + + Ok(proto::Room { + id: db_room.id as u64, + live_kit_room: db_room.live_kit_room, + participants: participants.into_values().collect(), + pending_participants, + }) + } + + async fn commit_room_transaction( + &self, + room_id: RoomId, + tx: DatabaseTransaction, + data: T, + ) -> Result> { + let lock = self.rooms.entry(room_id).or_default().clone(); + let _guard = lock.lock_owned().await; + tx.commit().await?; + Ok(RoomGuard { + data, + _guard, + _not_send: PhantomData, + }) + } + + async fn transact(&self, f: F) -> Result + where + F: Send + Fn(DatabaseTransaction) -> Fut, + Fut: Send + Future>, + { + let body = async { + loop { + let tx = self.pool.begin().await?; + match f(tx).await { + Ok(result) => return Ok(result), + Err(error) => match error { + Error::Database2( + DbErr::Exec(sea_orm::RuntimeErr::SqlxError(error)) + | DbErr::Query(sea_orm::RuntimeErr::SqlxError(error)), + ) if error + .as_database_error() + .and_then(|error| error.code()) + .as_deref() + == Some("40001") => + { + // Retry (don't break the loop) + } + error @ _ => return Err(error), + }, + } + } + }; + + #[cfg(test)] + { + if let Some(background) = self.background.as_ref() { + background.simulate_random_delay().await; + } + + self.runtime.as_ref().unwrap().block_on(body) + } + + #[cfg(not(test))] + { + body.await + } + } +} + +pub struct RoomGuard { + data: T, + _guard: OwnedMutexGuard<()>, + _not_send: PhantomData>, +} + +impl Deref for RoomGuard { + type Target = T; + + fn deref(&self) -> &T { + &self.data + } +} + +impl DerefMut for RoomGuard { + fn deref_mut(&mut self) -> &mut T { + &mut self.data + } +} + +macro_rules! id_type { + ($name:ident) => { + #[derive( + Clone, + Copy, + Debug, + Default, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + sqlx::Type, + Serialize, + Deserialize, + )] + #[sqlx(transparent)] + #[serde(transparent)] + pub struct $name(pub i32); + + impl $name { + #[allow(unused)] + pub const MAX: Self = Self(i32::MAX); + + #[allow(unused)] + pub fn from_proto(value: u64) -> Self { + Self(value as i32) + } + + #[allow(unused)] + pub fn to_proto(self) -> u64 { + self.0 as u64 + } + } + + impl std::fmt::Display for $name { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + self.0.fmt(f) + } + } + }; +} + +id_type!(UserId); +id_type!(RoomId); +id_type!(RoomParticipantId); +id_type!(ProjectId); +id_type!(WorktreeId); diff --git a/crates/collab/src/db2/project.rs b/crates/collab/src/db2/project.rs new file mode 100644 index 0000000000..4ae0616835 --- /dev/null +++ b/crates/collab/src/db2/project.rs @@ -0,0 +1,37 @@ +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)] +#[sea_orm(table_name = "projects")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub room_id: i32, + pub host_user_id: i32, + pub host_connection_id: i32, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::room::Entity", + from = "Column::RoomId", + to = "super::room::Column::Id" + )] + Room, + #[sea_orm(has_many = "super::worktree::Entity")] + Worktree, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Room.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Worktree.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/crates/collab/src/db2/project_collaborator.rs b/crates/collab/src/db2/project_collaborator.rs new file mode 100644 index 0000000000..da567eb2c2 --- /dev/null +++ b/crates/collab/src/db2/project_collaborator.rs @@ -0,0 +1,18 @@ +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)] +#[sea_orm(table_name = "project_collaborators")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub project_id: i32, + pub connection_id: i32, + pub user_id: i32, + pub replica_id: i32, + pub is_host: bool, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/crates/collab/src/db2/room.rs b/crates/collab/src/db2/room.rs new file mode 100644 index 0000000000..18f1d234e5 --- /dev/null +++ b/crates/collab/src/db2/room.rs @@ -0,0 +1,31 @@ +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)] +#[sea_orm(table_name = "room_participants")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub live_kit_room: String, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm(has_many = "super::room_participant::Entity")] + RoomParticipant, + #[sea_orm(has_many = "super::project::Entity")] + Project, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::RoomParticipant.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Project.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/crates/collab/src/db2/room_participant.rs b/crates/collab/src/db2/room_participant.rs new file mode 100644 index 0000000000..c9b7a13e07 --- /dev/null +++ b/crates/collab/src/db2/room_participant.rs @@ -0,0 +1,34 @@ +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)] +#[sea_orm(table_name = "room_participants")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub room_id: i32, + pub user_id: i32, + pub answering_connection_id: Option, + pub location_kind: Option, + pub location_project_id: Option, + pub initial_project_id: Option, + pub calling_user_id: i32, + pub calling_connection_id: i32, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::room::Entity", + from = "Column::RoomId", + to = "super::room::Column::Id" + )] + Room, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Room.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/crates/collab/src/db2/worktree.rs b/crates/collab/src/db2/worktree.rs new file mode 100644 index 0000000000..3a630fcfc9 --- /dev/null +++ b/crates/collab/src/db2/worktree.rs @@ -0,0 +1,33 @@ +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)] +#[sea_orm(table_name = "worktrees")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + #[sea_orm(primary_key)] + pub project_id: i32, + pub abs_path: String, + pub root_name: String, + pub visible: bool, + pub scan_id: i64, + pub is_complete: bool, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::project::Entity", + from = "Column::ProjectId", + to = "super::project::Column::Id" + )] + Project, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Project.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/crates/collab/src/lib.rs b/crates/collab/src/lib.rs index be21999a45..23af3344b5 100644 --- a/crates/collab/src/lib.rs +++ b/crates/collab/src/lib.rs @@ -5,6 +5,7 @@ pub type Result = std::result::Result; pub enum Error { Http(StatusCode, String), Database(sqlx::Error), + Database2(sea_orm::error::DbErr), Internal(anyhow::Error), } @@ -20,6 +21,12 @@ impl From for Error { } } +impl From for Error { + fn from(error: sea_orm::error::DbErr) -> Self { + Self::Database2(error) + } +} + impl From for Error { fn from(error: axum::Error) -> Self { Self::Internal(error.into()) @@ -45,6 +52,9 @@ impl IntoResponse for Error { Error::Database(error) => { (StatusCode::INTERNAL_SERVER_ERROR, format!("{}", &error)).into_response() } + Error::Database2(error) => { + (StatusCode::INTERNAL_SERVER_ERROR, format!("{}", &error)).into_response() + } Error::Internal(error) => { (StatusCode::INTERNAL_SERVER_ERROR, format!("{}", &error)).into_response() } @@ -57,6 +67,7 @@ impl std::fmt::Debug for Error { match self { Error::Http(code, message) => (code, message).fmt(f), Error::Database(error) => error.fmt(f), + Error::Database2(error) => error.fmt(f), Error::Internal(error) => error.fmt(f), } } @@ -67,6 +78,7 @@ impl std::fmt::Display for Error { match self { Error::Http(code, message) => write!(f, "{code}: {message}"), Error::Database(error) => error.fmt(f), + Error::Database2(error) => error.fmt(f), Error::Internal(error) => error.fmt(f), } } diff --git a/crates/collab/src/main.rs b/crates/collab/src/main.rs index 019197fc46..8a2cdc980f 100644 --- a/crates/collab/src/main.rs +++ b/crates/collab/src/main.rs @@ -1,6 +1,7 @@ mod api; mod auth; mod db; +mod db2; mod env; mod rpc;