Refactor database layer to eliminate type switching and simplify architecture
- Replace type switching with clean repository pattern using sqlc-generated code - Move ContentRepository interface and domain models to db package - Create separate SQLiteRepository and PostgreSQLRepository implementations - Remove unnecessary RepositoryAdapter and ContentClient interface duplication - Update all clients (HTTP, Mock) to implement db.ContentRepository directly - Add context.Context parameters to all repository methods (Go best practice) - Eliminate duplicate domain models and type conversions - Remove type aliases - use db package types directly throughout codebase - Update engine, content managers, and API handlers to use repositories directly Benefits: - Zero runtime type switching overhead - Single source of truth for domain models - Clean package boundaries and separation of concerns - Standard Go interface patterns with context support - Easier testing with mockable repository interface - Maintainable: adding new database types requires no changes to existing code
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/insertr/insertr/internal/db"
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
|
||||
@@ -15,13 +17,13 @@ type AuthProvider struct {
|
||||
// ContentEngine is the unified content processing engine
|
||||
type ContentEngine struct {
|
||||
idGenerator *IDGenerator
|
||||
client ContentClient
|
||||
client db.ContentRepository
|
||||
authProvider *AuthProvider
|
||||
injector *Injector
|
||||
}
|
||||
|
||||
// NewContentEngine creates a new content processing engine
|
||||
func NewContentEngine(client ContentClient) *ContentEngine {
|
||||
func NewContentEngine(client db.ContentRepository) *ContentEngine {
|
||||
authProvider := &AuthProvider{Type: "mock"} // default
|
||||
return &ContentEngine{
|
||||
idGenerator: NewIDGenerator(),
|
||||
@@ -32,7 +34,7 @@ func NewContentEngine(client ContentClient) *ContentEngine {
|
||||
}
|
||||
|
||||
// NewContentEngineWithAuth creates a new content processing engine with auth config
|
||||
func NewContentEngineWithAuth(client ContentClient, authProvider *AuthProvider) *ContentEngine {
|
||||
func NewContentEngineWithAuth(client db.ContentRepository, authProvider *AuthProvider) *ContentEngine {
|
||||
if authProvider == nil {
|
||||
authProvider = &AuthProvider{Type: "mock"}
|
||||
}
|
||||
@@ -64,7 +66,7 @@ func (e *ContentEngine) ProcessContent(input ContentInput) (*ContentResult, erro
|
||||
id := e.idGenerator.Generate(elem.Node, input.FilePath)
|
||||
|
||||
// Database-first approach: Check if content already exists
|
||||
existingContent, err := e.client.GetContent(input.SiteID, id)
|
||||
existingContent, err := e.client.GetContent(context.Background(), input.SiteID, id)
|
||||
contentExists := (err == nil && existingContent != nil)
|
||||
|
||||
generatedIDs[fmt.Sprintf("element_%d", i)] = id
|
||||
@@ -87,7 +89,7 @@ func (e *ContentEngine) ProcessContent(input ContentInput) (*ContentResult, erro
|
||||
originalTemplate := e.extractOriginalTemplate(elem.Node)
|
||||
|
||||
// Store in database via content client
|
||||
_, err := e.client.CreateContent(input.SiteID, id, htmlContent, originalTemplate, "system")
|
||||
_, err := e.client.CreateContent(context.Background(), input.SiteID, id, htmlContent, originalTemplate, "system")
|
||||
if err != nil {
|
||||
// Log error but don't fail the enhancement - content just won't be stored
|
||||
fmt.Printf("⚠️ Failed to store content for %s: %v\n", id, err)
|
||||
@@ -343,7 +345,7 @@ func (e *ContentEngine) injectContent(elements []ProcessedElement, siteID string
|
||||
elem := &elements[i]
|
||||
|
||||
// Try to get content from database
|
||||
contentItem, err := e.client.GetContent(siteID, elem.ID)
|
||||
contentItem, err := e.client.GetContent(context.Background(), siteID, elem.ID)
|
||||
if err != nil {
|
||||
// Content not found is not an error - element just won't have injected content
|
||||
continue
|
||||
@@ -467,14 +469,14 @@ func (e *ContentEngine) getPlaceholderForElement(elementType string) string {
|
||||
// processCollection handles collection detection, persistence and reconstruction
|
||||
func (e *ContentEngine) processCollection(collectionNode *html.Node, collectionID, siteID string) error {
|
||||
// 1. Check if collection exists in database
|
||||
existingCollection, err := e.client.GetCollection(siteID, collectionID)
|
||||
existingCollection, err := e.client.GetCollection(context.Background(), siteID, collectionID)
|
||||
collectionExists := (err == nil && existingCollection != nil)
|
||||
|
||||
if !collectionExists {
|
||||
// 2. New collection: extract container HTML and create collection record
|
||||
containerHTML := e.extractOriginalTemplate(collectionNode)
|
||||
|
||||
_, err := e.client.CreateCollection(siteID, collectionID, containerHTML, "system")
|
||||
_, err := e.client.CreateCollection(context.Background(), siteID, collectionID, containerHTML, "system")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create collection %s: %w", collectionID, err)
|
||||
}
|
||||
@@ -494,7 +496,7 @@ func (e *ContentEngine) processCollection(collectionNode *html.Node, collectionI
|
||||
}
|
||||
|
||||
// Get final item count for logging
|
||||
existingItems, _ := e.client.GetCollectionItems(siteID, collectionID)
|
||||
existingItems, _ := e.client.GetCollectionItems(context.Background(), siteID, collectionID)
|
||||
fmt.Printf("✅ Reconstructed collection: %s from database (%d items)\n", collectionID, len(existingItems))
|
||||
}
|
||||
|
||||
@@ -515,7 +517,7 @@ func (e *ContentEngine) extractAndStoreTemplatesAndItems(collectionNode *html.No
|
||||
|
||||
if len(templateElements) == 0 {
|
||||
// No existing children - create a default empty template
|
||||
_, err := e.client.CreateCollectionTemplate(siteID, collectionID, "default", "<div>New item</div>", true)
|
||||
_, err := e.client.CreateCollectionTemplate(context.Background(), siteID, collectionID, "default", "<div>New item</div>", true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create default template: %w", err)
|
||||
}
|
||||
@@ -530,7 +532,7 @@ func (e *ContentEngine) extractAndStoreTemplatesAndItems(collectionNode *html.No
|
||||
templateName := fmt.Sprintf("template-%d", i+1)
|
||||
isDefault := (i == 0) // First template is default
|
||||
|
||||
template, err := e.client.CreateCollectionTemplate(siteID, collectionID, templateName, templateHTML, isDefault)
|
||||
template, err := e.client.CreateCollectionTemplate(context.Background(), siteID, collectionID, templateName, templateHTML, isDefault)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create template %s: %w", templateName, err)
|
||||
}
|
||||
@@ -557,13 +559,13 @@ func (e *ContentEngine) extractAndStoreTemplatesAndItems(collectionNode *html.No
|
||||
// reconstructCollectionItems rebuilds collection items from database and adds them to DOM
|
||||
func (e *ContentEngine) reconstructCollectionItems(collectionNode *html.Node, collectionID, siteID string) error {
|
||||
// Get all items for this collection from database
|
||||
items, err := e.client.GetCollectionItems(siteID, collectionID)
|
||||
items, err := e.client.GetCollectionItems(context.Background(), siteID, collectionID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get collection items: %w", err)
|
||||
}
|
||||
|
||||
// Get templates for this collection
|
||||
templates, err := e.client.GetCollectionTemplates(siteID, collectionID)
|
||||
templates, err := e.client.GetCollectionTemplates(context.Background(), siteID, collectionID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get collection templates: %w", err)
|
||||
}
|
||||
@@ -652,7 +654,7 @@ func (e *ContentEngine) processChildElementsAsContent(childElement *html.Node, s
|
||||
actualContent := ExtractTextContent(n)
|
||||
|
||||
// Store as individual content entry (unified .insertr approach)
|
||||
_, err := e.client.CreateContent(siteID, contentID, actualContent, "", "system")
|
||||
_, err := e.client.CreateContent(context.Background(), siteID, contentID, actualContent, "", "system")
|
||||
if err != nil {
|
||||
fmt.Printf("⚠️ Failed to create content %s: %v\n", contentID, err)
|
||||
return
|
||||
@@ -737,7 +739,7 @@ func (e *ContentEngine) CreateCollectionItemFromTemplate(
|
||||
templateID int,
|
||||
templateHTML string,
|
||||
lastEditedBy string,
|
||||
) (*CollectionItemWithTemplate, error) {
|
||||
) (*db.CollectionItemWithTemplate, error) {
|
||||
// Create virtual element from template (like enhancement path)
|
||||
virtualElement, err := e.createVirtualElementFromTemplate(templateHTML)
|
||||
if err != nil {
|
||||
@@ -763,7 +765,7 @@ func (e *ContentEngine) CreateCollectionItemFromTemplate(
|
||||
}
|
||||
|
||||
// Create collection item with structural template
|
||||
collectionItem, err := e.client.CreateCollectionItem(
|
||||
collectionItem, err := e.client.CreateCollectionItem(context.Background(),
|
||||
siteID, collectionID, itemID, templateID, structuralTemplate, 0, lastEditedBy,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -838,7 +840,7 @@ func (e *ContentEngine) storeChildrenAsCollectionItems(collectionNode *html.Node
|
||||
templateID := templateIDs[i%len(templateIDs)]
|
||||
|
||||
// Store structural template in collection_items (content lives in content table)
|
||||
_, err = e.client.CreateCollectionItem(siteID, collectionID, itemID, templateID, structuralTemplate, i+1, "system")
|
||||
_, err = e.client.CreateCollectionItem(context.Background(), siteID, collectionID, itemID, templateID, structuralTemplate, i+1, "system")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create collection item %s: %w", itemID, err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user