From e957acbc23336146c490886e0f316c2b88d96718 Mon Sep 17 00:00:00 2001 From: Tianzhou Date: Sun, 12 Oct 2025 21:01:47 +0800 Subject: [PATCH] feat: MATERIALIZED VIEW COMMENT --- ir/parser.go | 34 ++++++++++ testdata/include/expected_full_schema.sql | 67 +++++++++++++++++++ testdata/include/main.sql | 4 ++ .../materialized_views/monthly_stats.sql | 36 ++++++++++ .../materialized_views/user_order_summary.sql | 29 ++++++++ 5 files changed, 170 insertions(+) create mode 100644 testdata/include/materialized_views/monthly_stats.sql create mode 100644 testdata/include/materialized_views/user_order_summary.sql diff --git a/ir/parser.go b/ir/parser.go index 16f78f65..ed0a08ac 100644 --- a/ir/parser.go +++ b/ir/parser.go @@ -3802,6 +3802,40 @@ func (p *Parser) parseComment(stmt *pg_query.CommentStmt) error { view.Comment = comment } } + + case pg_query.ObjectType_OBJECT_MATVIEW: + if stmt.Object == nil { + return nil + } + + // Extract materialized view name from object + var schemaName, viewName string + if rangeVar, ok := stmt.Object.Node.(*pg_query.Node_List); ok && rangeVar.List != nil { + items := rangeVar.List.Items + if len(items) == 2 { + // Schema and materialized view name + if s, ok := items[0].Node.(*pg_query.Node_String_); ok { + schemaName = s.String_.Sval + } + if v, ok := items[1].Node.(*pg_query.Node_String_); ok { + viewName = v.String_.Sval + } + } else if len(items) == 1 { + // Just materialized view name, use public schema + schemaName = p.defaultSchema + if v, ok := items[0].Node.(*pg_query.Node_String_); ok { + viewName = v.String_.Sval + } + } + } + + // Set comment on materialized view (stored in Views map with Materialized=true) + if schemaName != "" && viewName != "" { + dbSchema := p.schema.getOrCreateSchema(schemaName) + if view, exists := dbSchema.Views[viewName]; exists && view.Materialized { + view.Comment = comment + } + } } return nil diff --git a/testdata/include/expected_full_schema.sql b/testdata/include/expected_full_schema.sql index 73e83e2c..f21bda38 100644 --- a/testdata/include/expected_full_schema.sql +++ b/testdata/include/expected_full_schema.sql @@ -231,3 +231,70 @@ CREATE OR REPLACE VIEW order_details AS JOIN users u ON o.user_id = u.id; COMMENT ON VIEW order_details IS 'Order details with user info'; + +-- Include materialized views (depend on tables) +-- +-- Name: user_order_summary; Type: MATERIALIZED VIEW; Schema: -; Owner: - +-- + +CREATE MATERIALIZED VIEW IF NOT EXISTS user_order_summary AS + SELECT u.id AS user_id, + u.name, + u.email, + count(o.id) AS total_orders, + sum(o.amount) AS total_amount, + max(o.amount) AS max_order_amount, + avg(o.amount) AS avg_order_amount + FROM users u + LEFT JOIN orders o ON u.id = o.user_id + GROUP BY u.id, u.name, u.email; + +COMMENT ON MATERIALIZED VIEW user_order_summary IS 'Aggregated user order statistics'; + +-- +-- Name: idx_user_order_summary_total_amount; Type: INDEX; Schema: -; Owner: - +-- + +CREATE INDEX IF NOT EXISTS idx_user_order_summary_total_amount ON user_order_summary (total_amount DESC); + +-- +-- Name: idx_user_order_summary_user_id; Type: INDEX; Schema: -; Owner: - +-- + +CREATE UNIQUE INDEX IF NOT EXISTS idx_user_order_summary_user_id ON user_order_summary (user_id); +-- +-- Name: monthly_stats; Type: MATERIALIZED VIEW; Schema: -; Owner: - +-- + +CREATE MATERIALIZED VIEW IF NOT EXISTS monthly_stats AS + SELECT date_trunc('month'::text, now()) AS month, + count(user_id) AS unique_customers, + count(id) AS total_orders, + sum(amount) AS total_revenue, + avg(amount) AS avg_order_value, + count( + CASE + WHEN status = 'completed'::text THEN 1 + ELSE NULL::integer + END) AS completed_orders, + count( + CASE + WHEN status = 'pending'::text THEN 1 + ELSE NULL::integer + END) AS pending_orders + FROM orders o + GROUP BY (date_trunc('month'::text, now())); + +COMMENT ON MATERIALIZED VIEW monthly_stats IS 'Monthly order statistics'; + +-- +-- Name: idx_monthly_stats_month; Type: INDEX; Schema: -; Owner: - +-- + +CREATE UNIQUE INDEX IF NOT EXISTS idx_monthly_stats_month ON monthly_stats (month); + +-- +-- Name: idx_monthly_stats_revenue; Type: INDEX; Schema: -; Owner: - +-- + +CREATE INDEX IF NOT EXISTS idx_monthly_stats_revenue ON monthly_stats (total_revenue DESC); diff --git a/testdata/include/main.sql b/testdata/include/main.sql index 9e85278e..1d7bf164 100644 --- a/testdata/include/main.sql +++ b/testdata/include/main.sql @@ -30,3 +30,7 @@ -- Include views (depend on tables and functions) \i views/user_summary.sql \i views/order_details.sql + +-- Include materialized views (depend on tables) +\i materialized_views/user_order_summary.sql +\i materialized_views/monthly_stats.sql diff --git a/testdata/include/materialized_views/monthly_stats.sql b/testdata/include/materialized_views/monthly_stats.sql new file mode 100644 index 00000000..68821237 --- /dev/null +++ b/testdata/include/materialized_views/monthly_stats.sql @@ -0,0 +1,36 @@ +-- +-- Name: monthly_stats; Type: MATERIALIZED VIEW; Schema: -; Owner: - +-- + +CREATE MATERIALIZED VIEW IF NOT EXISTS monthly_stats AS + SELECT date_trunc('month'::text, now()) AS month, + count(user_id) AS unique_customers, + count(id) AS total_orders, + sum(amount) AS total_revenue, + avg(amount) AS avg_order_value, + count( + CASE + WHEN status = 'completed'::text THEN 1 + ELSE NULL::integer + END) AS completed_orders, + count( + CASE + WHEN status = 'pending'::text THEN 1 + ELSE NULL::integer + END) AS pending_orders + FROM orders o + GROUP BY (date_trunc('month'::text, now())); + +COMMENT ON MATERIALIZED VIEW monthly_stats IS 'Monthly order statistics'; + +-- +-- Name: idx_monthly_stats_month; Type: INDEX; Schema: -; Owner: - +-- + +CREATE UNIQUE INDEX IF NOT EXISTS idx_monthly_stats_month ON monthly_stats (month); + +-- +-- Name: idx_monthly_stats_revenue; Type: INDEX; Schema: -; Owner: - +-- + +CREATE INDEX IF NOT EXISTS idx_monthly_stats_revenue ON monthly_stats (total_revenue DESC); diff --git a/testdata/include/materialized_views/user_order_summary.sql b/testdata/include/materialized_views/user_order_summary.sql new file mode 100644 index 00000000..c12519c3 --- /dev/null +++ b/testdata/include/materialized_views/user_order_summary.sql @@ -0,0 +1,29 @@ +-- +-- Name: user_order_summary; Type: MATERIALIZED VIEW; Schema: -; Owner: - +-- + +CREATE MATERIALIZED VIEW IF NOT EXISTS user_order_summary AS + SELECT u.id AS user_id, + u.name, + u.email, + count(o.id) AS total_orders, + sum(o.amount) AS total_amount, + max(o.amount) AS max_order_amount, + avg(o.amount) AS avg_order_amount + FROM users u + LEFT JOIN orders o ON u.id = o.user_id + GROUP BY u.id, u.name, u.email; + +COMMENT ON MATERIALIZED VIEW user_order_summary IS 'Aggregated user order statistics'; + +-- +-- Name: idx_user_order_summary_total_amount; Type: INDEX; Schema: -; Owner: - +-- + +CREATE INDEX IF NOT EXISTS idx_user_order_summary_total_amount ON user_order_summary (total_amount DESC); + +-- +-- Name: idx_user_order_summary_user_id; Type: INDEX; Schema: -; Owner: - +-- + +CREATE UNIQUE INDEX IF NOT EXISTS idx_user_order_summary_user_id ON user_order_summary (user_id);