Skip to content

Commit dbb9729

Browse files
committed
Zedium v1.7.2-3: track upstream v1.7.2
1 parent 60b5c31 commit dbb9729

137 files changed

Lines changed: 170702 additions & 150365 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

patches/0003-strip-remove-auto_update-auto_update_ui-auto_update_.patch

Lines changed: 5481 additions & 6284 deletions
Large diffs are not rendered by default.

patches/0032-strip-remove-packaging-rebrand-desktop-cli-install-Z.patch

Lines changed: 134881 additions & 144081 deletions
Large diffs are not rendered by default.
Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2+
From: IamMaxim <g.maxim.stepanoff@gmail.com>
3+
Date: Tue, 30 Jun 2026 20:05:35 +0300
4+
Subject: [PATCH] fix(db): exclude internal pg_* schemas from explorer tree
5+
6+
The schema explorer leaked `pg_toast` (and other `pg_*` internal
7+
schemas) as non-expandable dead-end nodes because the schema filter
8+
only excluded `pg_catalog` and `information_schema`. Switch to a
9+
`not like 'pg\_%'` filter so all internal schemas are excluded, leaving
10+
only user schemas (public, app, ...) that actually expand.
11+
12+
Add live introspection tests (schemas/relations/columns) and a live
13+
panel test that drives lazy expansion connection -> schema -> relation
14+
-> columns against a real Postgres, plus the test-support dev-deps and
15+
gpui_tokio/allow_parking setup the existing connect_and_select test was
16+
missing.
17+
18+
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
19+
Claude-Session: https://claude.ai/code/session_01GbHBSdw2MBBgxKxLnVCbf6
20+
---
21+
Cargo.lock | 1 +
22+
crates/database_client/Cargo.toml | 4 +
23+
.../database_client/src/connection/client.rs | 2 +
24+
.../src/connection/introspect.rs | 69 ++++++++-
25+
crates/database_client/src/panel.rs | 138 ++++++++++++++++++
26+
5 files changed, 213 insertions(+), 1 deletion(-)
27+
28+
diff --git a/Cargo.lock b/Cargo.lock
29+
index c0f136430c..e061529963 100644
30+
--- a/Cargo.lock
31+
+++ b/Cargo.lock
32+
@@ -3755,6 +3755,7 @@ dependencies = [
33+
"anyhow",
34+
"db",
35+
"editor",
36+
+ "fs",
37+
"futures 0.3.32",
38+
"gpui",
39+
"gpui_tokio",
40+
diff --git a/crates/database_client/Cargo.toml b/crates/database_client/Cargo.toml
41+
index 9303062449..b564819821 100644
42+
--- a/crates/database_client/Cargo.toml
43+
+++ b/crates/database_client/Cargo.toml
44+
@@ -43,6 +43,10 @@ zed_actions.workspace = true
45+
[dev-dependencies]
46+
db = { workspace = true, features = ["test-support"] }
47+
gpui = { workspace = true, features = ["test-support"] }
48+
+project = { workspace = true, features = ["test-support"] }
49+
+workspace = { workspace = true, features = ["test-support"] }
50+
+settings = { workspace = true, features = ["test-support"] }
51+
+fs = { workspace = true, features = ["test-support"] }
52+
tempfile.workspace = true
53+
54+
[package.metadata.cargo-machete]
55+
diff --git a/crates/database_client/src/connection/client.rs b/crates/database_client/src/connection/client.rs
56+
index a02ae0ceff..14e3febad2 100644
57+
--- a/crates/database_client/src/connection/client.rs
58+
+++ b/crates/database_client/src/connection/client.rs
59+
@@ -155,6 +155,8 @@ mod tests {
60+
let Ok(url) = std::env::var("DATABASE_CLIENT_TEST_PG_URL") else {
61+
return;
62+
};
63+
+ cx.executor().allow_parking();
64+
+ cx.update(|cx| gpui_tokio::init(cx));
65+
let profile = crate::connection::profile::ConnectionProfile::from_url(&url).unwrap();
66+
let password = profile_password_from_url(&url);
67+
let conn = cx
68+
diff --git a/crates/database_client/src/connection/introspect.rs b/crates/database_client/src/connection/introspect.rs
69+
index b2c878a1bc..e53e190c7a 100644
70+
--- a/crates/database_client/src/connection/introspect.rs
71+
+++ b/crates/database_client/src/connection/introspect.rs
72+
@@ -81,7 +81,7 @@ pub(crate) fn quote_ident(s: &str) -> String {
73+
impl Connection {
74+
pub fn list_schemas(&self, cx: &App) -> Task<Result<Vec<SchemaInfo>>> {
75+
let sql = "select schema_name from information_schema.schemata \
76+
- where schema_name not in ('pg_catalog','information_schema') \
77+
+ where schema_name not like 'pg\\_%' and schema_name <> 'information_schema' \
78+
order by schema_name"
79+
.to_string();
80+
let task = self.execute(sql, 10_000, cx);
81+
@@ -175,4 +175,71 @@ mod tests {
82+
assert_eq!(quote_ident("order"), "\"order\"");
83+
assert_eq!(quote_ident("we\"ird"), "\"we\"\"ird\"");
84+
}
85+
+
86+
+ // Live introspection tests against a real Postgres. Run with:
87+
+ // DATABASE_CLIENT_TEST_PG_URL=postgres://postgres:secret@localhost:55432/testdb?sslmode=disable \
88+
+ // cargo test -p database_client --lib -- --ignored live_
89+
+ #[cfg(test)]
90+
+ async fn live_connection(cx: &mut gpui::TestAppContext) -> Option<Connection> {
91+
+ use std::str::FromStr as _;
92+
+ let url = std::env::var("DATABASE_CLIENT_TEST_PG_URL").ok()?;
93+
+ cx.executor().allow_parking();
94+
+ cx.update(|cx| gpui_tokio::init(cx));
95+
+ let profile = crate::connection::profile::ConnectionProfile::from_url(&url).unwrap();
96+
+ let password = tokio_postgres::Config::from_str(&url)
97+
+ .ok()
98+
+ .and_then(|cfg| cfg.get_password().and_then(|p| String::from_utf8(p.to_vec()).ok()));
99+
+ Some(
100+
+ cx.update(|cx| Connection::connect(profile, password, cx))
101+
+ .await
102+
+ .unwrap(),
103+
+ )
104+
+ }
105+
+
106+
+ #[gpui::test]
107+
+ #[ignore]
108+
+ async fn live_list_schemas(cx: &mut gpui::TestAppContext) {
109+
+ let Some(conn) = live_connection(cx).await else {
110+
+ return;
111+
+ };
112+
+ let schemas = cx.update(|cx| conn.list_schemas(cx)).await.unwrap();
113+
+ let names: Vec<_> = schemas.iter().map(|s| s.name.as_str()).collect();
114+
+ assert!(names.contains(&"public"), "expected public schema, got {names:?}");
115+
+ assert!(names.contains(&"app"), "expected app schema, got {names:?}");
116+
+ assert!(
117+
+ !names.iter().any(|n| n.starts_with("pg_")),
118+
+ "internal pg_* schemas should be filtered out, got {names:?}"
119+
+ );
120+
+ }
121+
+
122+
+ #[gpui::test]
123+
+ #[ignore]
124+
+ async fn live_list_relations(cx: &mut gpui::TestAppContext) {
125+
+ let Some(conn) = live_connection(cx).await else {
126+
+ return;
127+
+ };
128+
+ let relations = cx
129+
+ .update(|cx| conn.list_relations("public".to_string(), cx))
130+
+ .await
131+
+ .unwrap();
132+
+ let by_name: std::collections::HashMap<_, _> =
133+
+ relations.iter().map(|r| (r.name.as_str(), r.kind)).collect();
134+
+ assert_eq!(by_name.get("users"), Some(&RelationKind::Table));
135+
+ assert_eq!(by_name.get("orders"), Some(&RelationKind::Table));
136+
+ assert_eq!(by_name.get("user_emails"), Some(&RelationKind::View));
137+
+ }
138+
+
139+
+ #[gpui::test]
140+
+ #[ignore]
141+
+ async fn live_list_columns(cx: &mut gpui::TestAppContext) {
142+
+ let Some(conn) = live_connection(cx).await else {
143+
+ return;
144+
+ };
145+
+ let columns = cx
146+
+ .update(|cx| conn.list_columns("public".to_string(), "users".to_string(), cx))
147+
+ .await
148+
+ .unwrap();
149+
+ let names: Vec<_> = columns.iter().map(|c| c.name.as_str()).collect();
150+
+ assert_eq!(names, vec!["id", "name", "email"]);
151+
+ }
152+
}
153+
diff --git a/crates/database_client/src/panel.rs b/crates/database_client/src/panel.rs
154+
index ad9c8951b3..cb6e8d094d 100644
155+
--- a/crates/database_client/src/panel.rs
156+
+++ b/crates/database_client/src/panel.rs
157+
@@ -614,3 +614,141 @@ impl Render for DatabasePanel {
158+
}))
159+
}
160+
}
161+
+
162+
+#[cfg(test)]
163+
+mod tests {
164+
+ use super::*;
165+
+ use crate::connection::profile::{ConnectionProfile, SslMode};
166+
+ use gpui::TestAppContext;
167+
+ use std::time::Duration;
168+
+
169+
+ fn init_test(cx: &mut TestAppContext) {
170+
+ cx.update(|cx| {
171+
+ let settings_store = settings::SettingsStore::test(cx);
172+
+ cx.set_global(settings_store);
173+
+ cx.set_global(db::AppDatabase::test_new());
174+
+ theme_settings::init(theme::LoadThemes::JustBase, cx);
175+
+ gpui_tokio::init(cx);
176+
+ });
177+
+ }
178+
+
179+
+ /// Build a panel backed by a single injected profile, bypassing on-disk profile loading.
180+
+ async fn panel_with_profile<'a>(
181+
+ profile: ConnectionProfile,
182+
+ cx: &'a mut TestAppContext,
183+
+ ) -> (Entity<DatabasePanel>, &'a mut gpui::VisualTestContext) {
184+
+ let fs = fs::FakeFs::new(cx.executor());
185+
+ let project = project::Project::test(fs, [], cx).await;
186+
+ let (workspace, cx) =
187+
+ cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx));
188+
+ let panel = workspace.update_in(cx, |workspace, window, cx| {
189+
+ DatabasePanel::new(workspace, window, cx)
190+
+ });
191+
+ panel.update(cx, |panel, cx| {
192+
+ panel.profiles = vec![profile];
193+
+ panel.tree = DatabasePanel::build_tree(&panel.profiles);
194+
+ panel.connections.clear();
195+
+ cx.notify();
196+
+ });
197+
+ (panel, cx)
198+
+ }
199+
+
200+
+ async fn wait_until(
201+
+ panel: &Entity<DatabasePanel>,
202+
+ cx: &mut gpui::VisualTestContext,
203+
+ description: &str,
204+
+ predicate: impl Fn(&DatabasePanel) -> bool,
205+
+ ) {
206+
+ for _ in 0..200 {
207+
+ cx.run_until_parked();
208+
+ if panel.read_with(cx, |panel, _| predicate(panel)) {
209+
+ return;
210+
+ }
211+
+ cx.background_executor.timer(Duration::from_millis(25)).await;
212+
+ }
213+
+ let labels = panel.read_with(cx, |panel, _| {
214+
+ panel
215+
+ .tree
216+
+ .visible_nodes()
217+
+ .iter()
218+
+ .map(|n| n.label.clone())
219+
+ .collect::<Vec<_>>()
220+
+ });
221+
+ let errors = panel.read_with(cx, |panel, _| panel.errors.clone());
222+
+ panic!("timed out waiting for {description}; visible={labels:?} errors={errors:?}");
223+
+ }
224+
+
225+
+ fn labels(panel: &Entity<DatabasePanel>, cx: &mut gpui::VisualTestContext) -> Vec<String> {
226+
+ panel.read_with(cx, |panel, _| {
227+
+ panel
228+
+ .tree
229+
+ .visible_nodes()
230+
+ .iter()
231+
+ .map(|n| n.label.clone())
232+
+ .collect()
233+
+ })
234+
+ }
235+
+
236+
+ // Drives the real panel expand orchestration against a live Postgres. Run with:
237+
+ // DATABASE_CLIENT_TEST_PG_URL=postgres://postgres@localhost:55432/testdb?sslmode=disable \
238+
+ // cargo test -p database_client --lib -- --ignored live_panel
239+
+ #[gpui::test]
240+
+ #[ignore]
241+
+ async fn live_panel_expands_connection_schema_relation_columns(cx: &mut TestAppContext) {
242+
+ let Ok(url) = std::env::var("DATABASE_CLIENT_TEST_PG_URL") else {
243+
+ return;
244+
+ };
245+
+ cx.executor().allow_parking();
246+
+ init_test(cx);
247+
+
248+
+ let mut profile = ConnectionProfile::from_url(&url).expect("valid test url");
249+
+ profile.id = "p1".into();
250+
+ profile.ssl_mode = SslMode::Disable;
251+
+
252+
+ let (panel, cx) = panel_with_profile(profile, cx).await;
253+
+
254+
+ // Expand connection -> schemas load.
255+
+ panel.update(cx, |panel, cx| panel.toggle_node("p1".into(), cx));
256+
+ wait_until(&panel, cx, "schemas to load", |panel| {
257+
+ panel.tree.schemas_loaded("p1")
258+
+ })
259+
+ .await;
260+
+ let schema_labels = labels(&panel, cx);
261+
+ assert!(
262+
+ schema_labels.contains(&"public".to_string()),
263+
+ "expected public schema, got {schema_labels:?}"
264+
+ );
265+
+ assert!(
266+
+ !schema_labels.iter().any(|l| l.starts_with("pg_")),
267+
+ "internal pg_* schemas should not appear, got {schema_labels:?}"
268+
+ );
269+
+
270+
+ // Expand the public schema -> relations load.
271+
+ panel.update(cx, |panel, cx| {
272+
+ panel.toggle_node("p1/public".into(), cx)
273+
+ });
274+
+ wait_until(&panel, cx, "relations to load", |panel| {
275+
+ panel.tree.relations_loaded("p1/public")
276+
+ })
277+
+ .await;
278+
+ let relation_labels = labels(&panel, cx);
279+
+ assert!(
280+
+ relation_labels.contains(&"users".to_string()),
281+
+ "expected users table under public, got {relation_labels:?}"
282+
+ );
283+
+
284+
+ // Expand the users relation -> columns load.
285+
+ panel.update(cx, |panel, cx| {
286+
+ panel.toggle_node("p1/public/users".into(), cx)
287+
+ });
288+
+ wait_until(&panel, cx, "columns to load", |panel| {
289+
+ panel.tree.columns_loaded("p1/public/users")
290+
+ })
291+
+ .await;
292+
+ let column_labels = labels(&panel, cx);
293+
+ assert!(
294+
+ column_labels.iter().any(|l| l.starts_with("id:")),
295+
+ "expected id column under users, got {column_labels:?}"
296+
+ );
297+
+ }
298+
+}

0 commit comments

Comments
 (0)