WIP
This commit is contained in:
parent
40c293e184
commit
bb70901e71
9 changed files with 310 additions and 9 deletions
|
@ -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"
|
"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");
|
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 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");
|
||||||
|
|
19
crates/collab/migrations/20230727150500_add_channels.sql
Normal file
19
crates/collab/migrations/20230727150500_add_channels.sql
Normal file
|
@ -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 access_token;
|
||||||
|
mod channel;
|
||||||
|
mod channel_member;
|
||||||
|
mod channel_parent;
|
||||||
mod contact;
|
mod contact;
|
||||||
mod follower;
|
mod follower;
|
||||||
mod language_server;
|
mod language_server;
|
||||||
|
@ -36,7 +39,7 @@ use sea_orm::{
|
||||||
DbErr, FromQueryResult, IntoActiveModel, IsolationLevel, JoinType, QueryOrder, QuerySelect,
|
DbErr, FromQueryResult, IntoActiveModel, IsolationLevel, JoinType, QueryOrder, QuerySelect,
|
||||||
Statement, TransactionTrait,
|
Statement, TransactionTrait,
|
||||||
};
|
};
|
||||||
use sea_query::{Alias, Expr, OnConflict, Query};
|
use sea_query::{Alias, Expr, OnConflict, Query, SelectStatement};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
pub use signup::{Invite, NewSignup, WaitlistSummary};
|
pub use signup::{Invite, NewSignup, WaitlistSummary};
|
||||||
use sqlx::migrate::{Migrate, Migration, MigrationSource};
|
use sqlx::migrate::{Migrate, Migration, MigrationSource};
|
||||||
|
@ -3027,6 +3030,138 @@ impl Database {
|
||||||
.await
|
.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>
|
async fn transaction<F, Fut, T>(&self, f: F) -> Result<T>
|
||||||
where
|
where
|
||||||
F: Send + Fn(TransactionHandle) -> Fut,
|
F: Send + Fn(TransactionHandle) -> Fut,
|
||||||
|
@ -3400,6 +3535,8 @@ macro_rules! id_type {
|
||||||
}
|
}
|
||||||
|
|
||||||
id_type!(AccessTokenId);
|
id_type!(AccessTokenId);
|
||||||
|
id_type!(ChannelId);
|
||||||
|
id_type!(ChannelMemberId);
|
||||||
id_type!(ContactId);
|
id_type!(ContactId);
|
||||||
id_type!(FollowerId);
|
id_type!(FollowerId);
|
||||||
id_type!(RoomId);
|
id_type!(RoomId);
|
||||||
|
|
39
crates/collab/src/db/channel.rs
Normal file
39
crates/collab/src/db/channel.rs
Normal file
|
@ -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()
|
||||||
|
// }
|
||||||
|
// }
|
59
crates/collab/src/db/channel_member.rs
Normal file
59
crates/collab/src/db/channel_member.rs
Normal file
|
@ -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(),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
13
crates/collab/src/db/channel_parent.rs
Normal file
13
crates/collab/src/db/channel_parent.rs
Normal file
|
@ -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 {}
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
|
@ -26,6 +26,8 @@ pub enum Relation {
|
||||||
RoomParticipant,
|
RoomParticipant,
|
||||||
#[sea_orm(has_many = "super::project::Entity")]
|
#[sea_orm(has_many = "super::project::Entity")]
|
||||||
HostedProjects,
|
HostedProjects,
|
||||||
|
#[sea_orm(has_many = "super::channel_member::Entity")]
|
||||||
|
ChannelMemberships,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Related<super::access_token::Entity> for Entity {
|
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 {}
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
|
@ -17,10 +17,7 @@ use gpui::{
|
||||||
Canvas, ChildView, Empty, Flex, Image, Label, List, ListOffset, ListState,
|
Canvas, ChildView, Empty, Flex, Image, Label, List, ListOffset, ListState,
|
||||||
MouseEventHandler, Orientation, Padding, ParentElement, Stack, Svg,
|
MouseEventHandler, Orientation, Padding, ParentElement, Stack, Svg,
|
||||||
},
|
},
|
||||||
geometry::{
|
geometry::{rect::RectF, vector::vec2f},
|
||||||
rect::RectF,
|
|
||||||
vector::vec2f,
|
|
||||||
},
|
|
||||||
platform::{CursorStyle, MouseButton, PromptLevel},
|
platform::{CursorStyle, MouseButton, PromptLevel},
|
||||||
serde_json, AnyElement, AppContext, AsyncAppContext, Element, Entity, ModelHandle,
|
serde_json, AnyElement, AppContext, AsyncAppContext, Element, Entity, ModelHandle,
|
||||||
Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle,
|
Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle,
|
||||||
|
@ -1452,11 +1449,8 @@ impl View for CollabPanel {
|
||||||
.with_child(ChildView::new(&self.context_menu, cx))
|
.with_child(ChildView::new(&self.context_menu, cx))
|
||||||
.into_any()
|
.into_any()
|
||||||
})
|
})
|
||||||
.on_click(MouseButton::Left, |_, v, cx| {
|
.on_click(MouseButton::Left, |_, _, cx| cx.focus_self())
|
||||||
cx.focus_self()
|
|
||||||
})
|
|
||||||
.into_any_named("channels panel")
|
.into_any_named("channels panel")
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue