(desiredView *View)
| 2155 | } |
| 2156 | |
| 2157 | func (g *Generator) generateDDLsForCreateView(desiredView *View) ([]string, error) { |
| 2158 | var ddls []string |
| 2159 | |
| 2160 | currentView := g.findViewByName(g.currentViews, desiredView.name) |
| 2161 | if currentView == nil { |
| 2162 | // View not found, add view. |
| 2163 | ddls = append(ddls, desiredView.statement) |
| 2164 | view := *desiredView // copy view |
| 2165 | // Don't copy indexes from desired to current - they'll be added when the CREATE INDEX is processed |
| 2166 | view.indexes = []Index{} |
| 2167 | g.currentViews = append(g.currentViews, &view) |
| 2168 | } else if desiredView.viewType == "VIEW" { // TODO: Fix the definition comparison for materialized views and enable this |
| 2169 | // View found. If it's different, create or replace view. |
| 2170 | // Use AST-based comparison with table lookup for SELECT * expansion |
| 2171 | tableLookup := g.createTableLookup() |
| 2172 | currentNormalizedAST := normalizeViewDefinition(currentView.definition, g.mode, tableLookup) |
| 2173 | desiredNormalizedAST := normalizeViewDefinition(desiredView.definition, g.mode, tableLookup) |
| 2174 | currentNormalized := strings.ToLower(parser.String(currentNormalizedAST)) |
| 2175 | desiredNormalized := strings.ToLower(parser.String(desiredNormalizedAST)) |
| 2176 | |
| 2177 | // Post-normalization fix for generic parser: strip remaining table qualifiers |
| 2178 | // The generic parser's ColName.Name may not respect the empty qualifier we set |
| 2179 | if g.mode == GeneratorModePostgres { |
| 2180 | currentNormalized = stripTableQualifiers(currentNormalized) |
| 2181 | desiredNormalized = stripTableQualifiers(desiredNormalized) |
| 2182 | } |
| 2183 | slog.Debug("Comparing view definitions", |
| 2184 | "current_before_norm", parser.String(currentView.definition), |
| 2185 | "desired_before_norm", parser.String(desiredView.definition), |
| 2186 | "current_after_norm", currentNormalized, |
| 2187 | "desired_after_norm", desiredNormalized, |
| 2188 | ) |
| 2189 | |
| 2190 | if currentNormalized != desiredNormalized { |
| 2191 | viewDefinition := parser.String(desiredView.definition) |
| 2192 | |
| 2193 | // Build the WITH [NO] DATA clause for materialized views |
| 2194 | withDataClause := "" |
| 2195 | if desiredView.withNoData { |
| 2196 | withDataClause = " WITH NO DATA" |
| 2197 | } else if desiredView.withData { |
| 2198 | withDataClause = " WITH DATA" |
| 2199 | } |
| 2200 | |
| 2201 | viewName := g.escapeViewName(desiredView) |
| 2202 | if g.shouldDropAndCreateView(currentView, desiredView) { |
| 2203 | // When dropping views that may have dependents, we need to handle them |
| 2204 | // For PostgreSQL, find dependent views and recreate them after |
| 2205 | var dependentViewDDLs []string |
| 2206 | if g.mode == GeneratorModePostgres { |
| 2207 | // Find all views that depend on this view |
| 2208 | dependentViews := g.findDependentViews(desiredView.name) |
| 2209 | // Drop them first (in reverse dependency order) |
| 2210 | for i := len(dependentViews) - 1; i >= 0; i-- { |
| 2211 | depView := dependentViews[i] |
| 2212 | ddls = append(ddls, fmt.Sprintf("DROP %s %s", depView.viewType, g.escapeViewName(depView))) |
| 2213 | } |
| 2214 | // Store DDLs to recreate dependent views after the base view |
no test coverage detected