Get join_buffer_for_channel compiling

Max Brunsfeld and Mikayla created

Co-authored-by: Mikayla <mikayla@zed.dev>

Change summary

crates/collab/src/db/queries/buffers.rs    | 23 +++++---
crates/collab/src/db/tables/channel.rs     |  4 
crates/collab/src/db/tests/buffer_tests.rs | 67 ++++++++++++++++++-----
crates/collab/src/db/tests/db_tests.rs     | 29 ----------
crates/collab/src/rpc.rs                   | 14 +---
crates/rpc/proto/zed.proto                 |  1 
6 files changed, 73 insertions(+), 65 deletions(-)

Detailed changes

crates/collab/src/db/queries/buffers.rs 🔗

@@ -1,11 +1,6 @@
 use super::*;
 use prost::Message;
 
-pub struct ChannelBuffer {
-    pub base_text: String,
-    pub operations: Vec<proto::Operation>,
-}
-
 impl Database {
     pub async fn update_buffer(
         &self,
@@ -66,7 +61,7 @@ impl Database {
         channel_id: ChannelId,
         user_id: UserId,
         connection: ConnectionId,
-    ) -> Result<ChannelBuffer> {
+    ) -> Result<proto::OpenChannelBufferResponse> {
         self.transaction(|tx| async move {
             let tx = tx;
 
@@ -95,7 +90,7 @@ impl Database {
             };
 
             // Join the collaborators
-            let collaborators = buffer
+            let mut collaborators = buffer
                 .find_related(channel_buffer_collaborator::Entity)
                 .all(&*tx)
                 .await?;
@@ -107,7 +102,7 @@ impl Database {
             while replica_ids.contains(&replica_id) {
                 replica_id.0 += 1;
             }
-            channel_buffer_collaborator::ActiveModel {
+            let collaborator = channel_buffer_collaborator::ActiveModel {
                 buffer_id: ActiveValue::Set(buffer.id),
                 connection_id: ActiveValue::Set(connection.id as i32),
                 connection_server_id: ActiveValue::Set(ServerId(connection.owner_id as i32)),
@@ -117,6 +112,7 @@ impl Database {
             }
             .insert(&*tx)
             .await?;
+            collaborators.push(collaborator);
 
             // Assemble the buffer state
             let id = buffer.id;
@@ -172,9 +168,18 @@ impl Database {
                 })
             }
 
-            Ok(ChannelBuffer {
+            Ok(proto::OpenChannelBufferResponse {
+                buffer_id: buffer.id.to_proto(),
                 base_text,
                 operations,
+                collaborators: collaborators
+                    .into_iter()
+                    .map(|collaborator| proto::Collaborator {
+                        peer_id: Some(collaborator.connection().into()),
+                        user_id: collaborator.user_id.to_proto(),
+                        replica_id: collaborator.replica_id.0 as u32,
+                    })
+                    .collect(),
             })
         })
         .await

crates/collab/src/db/tables/channel.rs 🔗

@@ -1,4 +1,4 @@
-use crate::db::{BufferId, ChannelId};
+use crate::db::ChannelId;
 use sea_orm::entity::prelude::*;
 
 #[derive(Clone, Debug, Default, PartialEq, Eq, DeriveEntityModel)]
@@ -15,7 +15,7 @@ impl ActiveModelBehavior for ActiveModel {}
 pub enum Relation {
     #[sea_orm(has_one = "super::room::Entity")]
     Room,
-    #[sea_orm(has_one = "super::room::Entity")]
+    #[sea_orm(has_one = "super::buffer::Entity")]
     Buffer,
     #[sea_orm(has_many = "super::channel_member::Entity")]
     Member,

crates/collab/src/db/tests/buffer_tests.rs 🔗

@@ -3,9 +3,13 @@ use crate::test_both_dbs;
 use language::proto;
 use text::Buffer;
 
-test_both_dbs!(test_buffers, test_buffers_postgres, test_buffers_sqlite);
+test_both_dbs!(
+    test_channel_buffers,
+    test_channel_buffers_postgres,
+    test_channel_buffers_sqlite
+);
 
-async fn test_buffers(db: &Arc<Database>) {
+async fn test_channel_buffers(db: &Arc<Database>) {
     // Prep database test info
     let a_id = db
         .create_user(
@@ -48,6 +52,8 @@ async fn test_buffers(db: &Arc<Database>) {
         .unwrap()
         .user_id;
 
+    let owner_id = db.create_server("production").await.unwrap().0 as u32;
+
     let zed_id = db.create_root_channel("zed", "1", a_id).await.unwrap();
 
     db.invite_channel_member(zed_id, b_id, a_id, false)
@@ -58,16 +64,19 @@ async fn test_buffers(db: &Arc<Database>) {
         .await
         .unwrap();
 
-    // TODO: Join buffer
-    let buffer_id = db.get_or_create_buffer_for_channel(zed_id);
+    let buffer_response_a = db
+        .join_buffer_for_channel(zed_id, a_id, ConnectionId { owner_id, id: 1 })
+        .await
+        .unwrap();
+    let buffer_id = BufferId::from_proto(buffer_response_a.buffer_id);
 
-    let mut buffer = Buffer::new(0, 0, "".to_string());
+    let mut buffer_a = Buffer::new(0, 0, "".to_string());
     let mut operations = Vec::new();
-    operations.push(buffer.edit([(0..0, "hello world")]));
-    operations.push(buffer.edit([(5..5, ", cruel")]));
-    operations.push(buffer.edit([(0..5, "goodbye")]));
-    operations.push(buffer.undo().unwrap().1);
-    assert_eq!(buffer.text(), "hello, cruel world");
+    operations.push(buffer_a.edit([(0..0, "hello world")]));
+    operations.push(buffer_a.edit([(5..5, ", cruel")]));
+    operations.push(buffer_a.edit([(0..5, "goodbye")]));
+    operations.push(buffer_a.undo().unwrap().1);
+    assert_eq!(buffer_a.text(), "hello, cruel world");
 
     let operations = operations
         .into_iter()
@@ -76,11 +85,14 @@ async fn test_buffers(db: &Arc<Database>) {
 
     db.update_buffer(buffer_id, &operations).await.unwrap();
 
-    let buffer_data = db.open_buffer(buffer_id).await.unwrap();
+    let buffer_response_b = db
+        .join_buffer_for_channel(zed_id, b_id, ConnectionId { owner_id, id: 2 })
+        .await
+        .unwrap();
 
-    let mut buffer_2 = Buffer::new(0, 0, buffer_data.base_text);
-    buffer_2
-        .apply_ops(buffer_data.operations.into_iter().map(|operation| {
+    let mut buffer_b = Buffer::new(0, 0, buffer_response_b.base_text);
+    buffer_b
+        .apply_ops(buffer_response_b.operations.into_iter().map(|operation| {
             let operation = proto::deserialize_operation(operation).unwrap();
             if let language::Operation::Buffer(operation) = operation {
                 operation
@@ -90,5 +102,30 @@ async fn test_buffers(db: &Arc<Database>) {
         }))
         .unwrap();
 
-    assert_eq!(buffer_2.text(), "hello, cruel world");
+    assert_eq!(buffer_b.text(), "hello, cruel world");
+
+    // Ensure that C fails to open the buffer
+    assert!(db
+        .join_buffer_for_channel(zed_id, c_id, ConnectionId { owner_id, id: 3 })
+        .await
+        .is_err());
+
+    //Ensure that both collaborators have shown up
+    assert_eq!(
+        buffer_response_b.collaborators,
+        &[
+            rpc::proto::Collaborator {
+                user_id: a_id.to_proto(),
+                peer_id: Some(rpc::proto::PeerId { id: 1, owner_id }),
+                replica_id: 0,
+            },
+            rpc::proto::Collaborator {
+                user_id: b_id.to_proto(),
+                peer_id: Some(rpc::proto::PeerId { id: 2, owner_id }),
+                replica_id: 1,
+            }
+        ]
+    );
+
+    // Leave buffer
 }

crates/collab/src/db/tests/db_tests.rs 🔗

@@ -1329,35 +1329,6 @@ async fn test_channel_renames(db: &Arc<Database>) {
     assert!(bad_name_rename.is_err())
 }
 
-test_both_dbs!(
-    test_get_or_create_channel_buffer,
-    test_get_or_create_channel_buffer_postgres,
-    test_get_or_create_channel_buffer_sqlite
-);
-
-async fn test_get_or_create_channel_buffer(db: &Arc<Database>) {
-    let a_id = db
-        .create_user(
-            "user1@example.com",
-            false,
-            NewUserParams {
-                github_login: "user1".into(),
-                github_user_id: 5,
-                invite_count: 0,
-            },
-        )
-        .await
-        .unwrap()
-        .user_id;
-
-    let zed_id = db.create_root_channel("zed", "1", a_id).await.unwrap();
-
-    let first_buffer_id = db.get_or_create_buffer_for_channel(zed_id).await.unwrap();
-    let second_buffer_id = db.get_or_create_buffer_for_channel(zed_id).await.unwrap();
-
-    assert_eq!(first_buffer_id, second_buffer_id);
-}
-
 #[gpui::test]
 async fn test_multiple_signup_overwrite() {
     let test_db = TestDb::postgres(build_background_executor());

crates/collab/src/rpc.rs 🔗

@@ -2492,17 +2492,11 @@ async fn open_channel_buffer(
     let db = session.db().await;
     let channel_id = ChannelId::from_proto(request.channel_id);
 
-    let buffer_id = db.get_or_create_buffer_for_channel(channel_id).await?;
-
-    // TODO: join channel_buffer
-
-    let buffer = db.open_buffer(buffer_id).await?;
+    let open_response = db
+        .join_buffer_for_channel(channel_id, session.user_id, session.connection_id)
+        .await?;
 
-    response.send(OpenChannelBufferResponse {
-        buffer_id: buffer_id.to_proto(),
-        base_text: buffer.base_text,
-        operations: buffer.operations,
-    })?;
+    response.send(open_response)?;
 
     Ok(())
 }

crates/rpc/proto/zed.proto 🔗

@@ -966,6 +966,7 @@ message OpenChannelBufferResponse {
     uint64 buffer_id = 1;
     string base_text = 2;
     repeated Operation operations = 3;
+    repeated Collaborator collaborators = 4;
 }
 
 message CloseChannelBuffer {