Detailed changes
@@ -184,3 +184,29 @@ CREATE UNIQUE INDEX
"index_followers_on_project_id_and_leader_connection_server_id_and_leader_connection_id_and_follower_connection_server_id_and_follower_connection_id"
ON "followers" ("project_id", "leader_connection_server_id", "leader_connection_id", "follower_connection_server_id", "follower_connection_id");
CREATE INDEX "index_followers_on_room_id" ON "followers" ("room_id");
+
+CREATE TABLE "channels" (
+ "id" INTEGER PRIMARY KEY AUTOINCREMENT,
+ -- "id_path" TEXT NOT NULL,
+ "name" VARCHAR NOT NULL,
+ "room_id" INTEGER REFERENCES rooms (id) ON DELETE SET NULL,
+ "created_at" TIMESTAMP NOT NULL DEFAULT now
+)
+
+CREATE TABLE "channel_parents" (
+ "child_id" INTEGER NOT NULL REFERENCES channels (id) ON DELETE CASCADE,
+ "parent_id" INTEGER NOT NULL REFERENCES channels (id) ON DELETE CASCADE,
+ PRIMARY KEY(child_id, parent_id)
+)
+
+-- CREATE UNIQUE INDEX "index_channels_on_id_path" ON "channels" ("id_path");
+
+CREATE TABLE "channel_members" (
+ "id" INTEGER PRIMARY KEY AUTOINCREMENT,
+ "channel_id" INTEGER NOT NULL REFERENCES channels (id) ON DELETE CASCADE,
+ "user_id" INTEGER NOT NULL REFERENCES users (id) ON DELETE CASCADE,
+ "admin" BOOLEAN NOT NULL DEFAULT false,
+ "updated_at" TIMESTAMP NOT NULL DEFAULT now
+)
+
+CREATE UNIQUE INDEX "index_channel_members_on_channel_id_and_user_id" ON "channel_members" ("channel_id", "user_id");
@@ -0,0 +1,19 @@
+CREATE TABLE "channels" (
+ "id" SERIAL PRIMARY KEY,
+ "id_path" TEXT NOT NULL,
+ "name" VARCHAR NOT NULL,
+ "room_id" INTEGER REFERENCES rooms (id) ON DELETE SET NULL,
+ "created_at" TIMESTAMP NOT NULL DEFAULT now
+)
+
+CREATE UNIQUE INDEX "index_channels_on_id_path" ON "channels" ("id_path");
+
+CREATE TABLE "channel_members" (
+ "id" SERIAL PRIMARY KEY,
+ "channel_id" INTEGER NOT NULL REFERENCES channels (id) ON DELETE CASCADE,
+ "user_id" INTEGER NOT NULL REFERENCES users (id) ON DELETE CASCADE,
+ "admin" BOOLEAN NOT NULL DEFAULT false,
+ "updated_at" TIMESTAMP NOT NULL DEFAULT now
+)
+
+CREATE UNIQUE INDEX "index_channel_members_on_channel_id_and_user_id" ON "channel_members" ("channel_id", "user_id");
@@ -1,4 +1,7 @@
mod access_token;
+mod channel;
+mod channel_member;
+mod channel_parent;
mod contact;
mod follower;
mod language_server;
@@ -36,7 +39,7 @@ use sea_orm::{
DbErr, FromQueryResult, IntoActiveModel, IsolationLevel, JoinType, QueryOrder, QuerySelect,
Statement, TransactionTrait,
};
-use sea_query::{Alias, Expr, OnConflict, Query};
+use sea_query::{Alias, Expr, OnConflict, Query, SelectStatement};
use serde::{Deserialize, Serialize};
pub use signup::{Invite, NewSignup, WaitlistSummary};
use sqlx::migrate::{Migrate, Migration, MigrationSource};
@@ -3027,6 +3030,138 @@ impl Database {
.await
}
+ // channels
+
+ pub async fn get_channels(&self, user_id: UserId) -> Result<Vec<ChannelId>> {
+ self.transaction(|tx| async move {
+ let tx = tx;
+
+ let user = user::Model {
+ id: user_id,
+ ..Default::default()
+ };
+ let mut channel_ids = user
+ .find_related(channel_member::Entity)
+ .select_only()
+ .column(channel_member::Column::ChannelId)
+ .all(&*tx)
+ .await;
+
+ let descendants = Alias::new("descendants");
+ let cte_referencing = SelectStatement::new()
+ .column(channel_parent::Column::ChildId)
+ .from(channel::Entity)
+ .and_where(
+ Expr::col(channel_parent::Column::ParentId)
+ .in_subquery(SelectStatement::new().from(descendants).take())
+ );
+
+ /*
+ WITH RECURSIVE descendant_ids(id) AS (
+ $1
+ UNION ALL
+ SELECT child_id as id FROM channel_parents WHERE parent_id IN descendants
+ )
+ SELECT * from channels where id in descendant_ids
+ */
+
+
+ // WITH RECURSIVE descendants(id) AS (
+ // // SQL QUERY FOR SELECTING Initial IDs
+ // UNION
+ // SELECT id FROM ancestors WHERE p.parent = id
+ // )
+ // SELECT * FROM descendants;
+
+
+
+ // let descendant_channel_ids =
+
+
+
+ // let query = sea_query::Query::with().recursive(true);
+
+
+ for id_path in id_paths {
+ //
+ }
+
+
+ // zed/public/plugins
+ // zed/public/plugins/js
+ // zed/zed-livekit
+ // livekit/zed-livekit
+ // zed - 101
+ // livekit - 500
+ // zed-livekit - 510
+ // public - 150
+ // plugins - 200
+ // js - 300
+ //
+ // Channel, Parent - edges
+ // 510 - 500
+ // 510 - 101
+ //
+ // Given the channel 'Zed' (101)
+ // Select * from EDGES where parent = 101 => 510
+ //
+
+
+ "SELECT * from channels where id_path like '$1?'"
+
+ // https://www.postgresql.org/docs/current/queries-with.html
+ // https://www.sqlite.org/lang_with.html
+
+ "SELECT channel_id from channel_ancestors where ancestor_id IN $()"
+
+ // | channel_id | ancestor_ids |
+ // 150 150
+ // 150 101
+ // 200 101
+ // 300 101
+ // 200 150
+ // 300 150
+ // 300 200
+ //
+ // // | channel_id | ancestor_ids |
+ // 150 101
+ // 200 101
+ // 300 101
+ // 200 150
+ // 300 [150, 200]
+
+ channel::Entity::find()
+ .filter(channel::Column::IdPath.like(id_paths.unwrap()))
+
+ dbg!(&id_paths.unwrap()[0].id_path);
+
+ // let mut channel_members_by_channel_id = HashMap::new();
+ // for channel_member in channel_members {
+ // channel_members_by_channel_id
+ // .entry(channel_member.channel_id)
+ // .or_insert_with(Vec::new)
+ // .push(channel_member);
+ // }
+
+ // let mut channel_messages = channel_message::Entity::find()
+ // .filter(channel_message::Column::ChannelId.in_selection(channel_ids))
+ // .all(&*tx)
+ // .await?;
+
+ // let mut channel_messages_by_channel_id = HashMap::new();
+ // for channel_message in channel_messages {
+ // channel_messages_by_channel_id
+ // .entry(channel_message.channel_id)
+ // .or_insert_with(Vec::new)
+ // .push(channel_message);
+ // }
+
+ todo!();
+ // Ok(channels)
+ })
+ .await
+ }
+
async fn transaction<F, Fut, T>(&self, f: F) -> Result<T>
where
F: Send + Fn(TransactionHandle) -> Fut,
@@ -3400,6 +3535,8 @@ macro_rules! id_type {
}
id_type!(AccessTokenId);
+id_type!(ChannelId);
+id_type!(ChannelMemberId);
id_type!(ContactId);
id_type!(FollowerId);
id_type!(RoomId);
@@ -0,0 +1,39 @@
+use super::{ChannelId, RoomId};
+use sea_orm::entity::prelude::*;
+
+#[derive(Clone, Debug, Default, PartialEq, Eq, DeriveEntityModel)]
+#[sea_orm(table_name = "channels")]
+pub struct Model {
+ #[sea_orm(primary_key)]
+ pub id: ChannelId,
+ pub room_id: Option<RoomId>,
+ // pub id_path: String,
+}
+
+impl ActiveModelBehavior for ActiveModel {}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+ #[sea_orm(has_one = "super::room::Entity")]
+ Room,
+ #[sea_orm(has_many = "super::channel_member::Entity")]
+ Member,
+}
+
+impl Related<super::channel_member::Entity> for Entity {
+ fn to() -> RelationDef {
+ Relation::Member.def()
+ }
+}
+
+impl Related<super::room::Entity> for Entity {
+ fn to() -> RelationDef {
+ Relation::Room.def()
+ }
+}
+
+// impl Related<super::follower::Entity> for Entity {
+// fn to() -> RelationDef {
+// Relation::Follower.def()
+// }
+// }
@@ -0,0 +1,59 @@
+use crate::db::channel_member;
+
+use super::{ChannelId, ChannelMemberId, UserId};
+use sea_orm::entity::prelude::*;
+
+#[derive(Clone, Debug, Default, PartialEq, Eq, DeriveEntityModel)]
+#[sea_orm(table_name = "channel_members")]
+pub struct Model {
+ #[sea_orm(primary_key)]
+ pub id: ChannelMemberId,
+ pub channel_id: ChannelId,
+ pub user_id: UserId,
+}
+
+impl ActiveModelBehavior for ActiveModel {}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+ #[sea_orm(
+ belongs_to = "super::channel::Entity",
+ from = "Column::ChannelId",
+ to = "super::channel::Column::Id"
+ )]
+ Channel,
+ #[sea_orm(
+ belongs_to = "super::user::Entity",
+ from = "Column::UserId",
+ to = "super::user::Column::Id"
+ )]
+ User,
+}
+
+impl Related<super::channel::Entity> for Entity {
+ fn to() -> RelationDef {
+ Relation::Channel.def()
+ }
+}
+
+impl Related<super::user::Entity> for Entity {
+ fn to() -> RelationDef {
+ Relation::User.def()
+ }
+}
+
+#[derive(Debug)]
+pub struct UserToChannel;
+
+impl Linked for UserToChannel {
+ type FromEntity = super::user::Entity;
+
+ type ToEntity = super::channel::Entity;
+
+ fn link(&self) -> Vec<RelationDef> {
+ vec![
+ channel_member::Relation::User.def().rev(),
+ channel_member::Relation::Channel.def(),
+ ]
+ }
+}
@@ -0,0 +1,13 @@
+use super::ChannelId;
+use sea_orm::entity::prelude::*;
+
+#[derive(Clone, Debug, Default, PartialEq, Eq, DeriveEntityModel)]
+#[sea_orm(table_name = "channel_parents")]
+pub struct Model {
+ #[sea_orm(primary_key)]
+ pub child_id: ChannelId,
+ #[sea_orm(primary_key)]
+ pub parent_id: ChannelId,
+}
+
+impl ActiveModelBehavior for ActiveModel {}
@@ -37,4 +37,10 @@ impl Related<super::follower::Entity> for Entity {
}
}
+impl Related<super::channel::Entity> for Entity {
+ fn to() -> RelationDef {
+ Relation::Follower.def()
+ }
+}
+
impl ActiveModelBehavior for ActiveModel {}
@@ -26,6 +26,8 @@ pub enum Relation {
RoomParticipant,
#[sea_orm(has_many = "super::project::Entity")]
HostedProjects,
+ #[sea_orm(has_many = "super::channel_member::Entity")]
+ ChannelMemberships,
}
impl Related<super::access_token::Entity> for Entity {
@@ -46,4 +48,10 @@ impl Related<super::project::Entity> for Entity {
}
}
+impl Related<super::channel_member::Entity> for Entity {
+ fn to() -> RelationDef {
+ Relation::ChannelMemberships.def()
+ }
+}
+
impl ActiveModelBehavior for ActiveModel {}
@@ -17,10 +17,7 @@ use gpui::{
Canvas, ChildView, Empty, Flex, Image, Label, List, ListOffset, ListState,
MouseEventHandler, Orientation, Padding, ParentElement, Stack, Svg,
},
- geometry::{
- rect::RectF,
- vector::vec2f,
- },
+ geometry::{rect::RectF, vector::vec2f},
platform::{CursorStyle, MouseButton, PromptLevel},
serde_json, AnyElement, AppContext, AsyncAppContext, Element, Entity, ModelHandle,
Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle,
@@ -1452,11 +1449,8 @@ impl View for CollabPanel {
.with_child(ChildView::new(&self.context_menu, cx))
.into_any()
})
- .on_click(MouseButton::Left, |_, v, cx| {
- cx.focus_self()
- })
+ .on_click(MouseButton::Left, |_, _, cx| cx.focus_self())
.into_any_named("channels panel")
-
}
}