package engine import ( "context" "database/sql" "fmt" "github.com/insertr/insertr/internal/db" "github.com/insertr/insertr/internal/db/postgresql" "github.com/insertr/insertr/internal/db/sqlite" ) // Helper function to convert sql.NullString to string func getStringFromNullString(ns sql.NullString) string { if ns.Valid { return ns.String } return "" } // DatabaseClient implements ContentClient interface using the database type DatabaseClient struct { database *db.Database } // NewDatabaseClient creates a new database client func NewDatabaseClient(database *db.Database) *DatabaseClient { return &DatabaseClient{ database: database, } } // GetContent retrieves a single content item func (c *DatabaseClient) GetContent(siteID, contentID string) (*ContentItem, error) { switch c.database.GetDBType() { case "sqlite3": content, err := c.database.GetSQLiteQueries().GetContent(context.Background(), sqlite.GetContentParams{ ID: contentID, SiteID: siteID, }) if err != nil { return nil, err } return &ContentItem{ ID: content.ID, SiteID: content.SiteID, HTMLContent: content.HtmlContent, OriginalTemplate: getStringFromNullString(content.OriginalTemplate), LastEditedBy: content.LastEditedBy, }, nil case "postgresql": content, err := c.database.GetPostgreSQLQueries().GetContent(context.Background(), postgresql.GetContentParams{ ID: contentID, SiteID: siteID, }) if err != nil { return nil, err } return &ContentItem{ ID: content.ID, SiteID: content.SiteID, HTMLContent: content.HtmlContent, OriginalTemplate: getStringFromNullString(content.OriginalTemplate), LastEditedBy: content.LastEditedBy, }, nil default: return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType()) } } // GetBulkContent retrieves multiple content items func (c *DatabaseClient) GetBulkContent(siteID string, contentIDs []string) (map[string]ContentItem, error) { switch c.database.GetDBType() { case "sqlite3": contents, err := c.database.GetSQLiteQueries().GetBulkContent(context.Background(), sqlite.GetBulkContentParams{ SiteID: siteID, Ids: contentIDs, }) if err != nil { return nil, err } items := make(map[string]ContentItem) for _, content := range contents { items[content.ID] = ContentItem{ ID: content.ID, SiteID: content.SiteID, HTMLContent: content.HtmlContent, OriginalTemplate: getStringFromNullString(content.OriginalTemplate), LastEditedBy: content.LastEditedBy, } } return items, nil case "postgresql": contents, err := c.database.GetPostgreSQLQueries().GetBulkContent(context.Background(), postgresql.GetBulkContentParams{ SiteID: siteID, Ids: contentIDs, }) if err != nil { return nil, err } items := make(map[string]ContentItem) for _, content := range contents { items[content.ID] = ContentItem{ ID: content.ID, SiteID: content.SiteID, HTMLContent: content.HtmlContent, OriginalTemplate: getStringFromNullString(content.OriginalTemplate), LastEditedBy: content.LastEditedBy, } } return items, nil default: return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType()) } } // GetAllContent retrieves all content items for a site func (c *DatabaseClient) GetAllContent(siteID string) (map[string]ContentItem, error) { switch c.database.GetDBType() { case "sqlite3": contents, err := c.database.GetSQLiteQueries().GetAllContent(context.Background(), siteID) if err != nil { return nil, err } items := make(map[string]ContentItem) for _, content := range contents { items[content.ID] = ContentItem{ ID: content.ID, SiteID: content.SiteID, HTMLContent: content.HtmlContent, OriginalTemplate: getStringFromNullString(content.OriginalTemplate), LastEditedBy: content.LastEditedBy, } } return items, nil case "postgresql": contents, err := c.database.GetPostgreSQLQueries().GetAllContent(context.Background(), siteID) if err != nil { return nil, err } items := make(map[string]ContentItem) for _, content := range contents { items[content.ID] = ContentItem{ ID: content.ID, SiteID: content.SiteID, HTMLContent: content.HtmlContent, OriginalTemplate: getStringFromNullString(content.OriginalTemplate), LastEditedBy: content.LastEditedBy, } } return items, nil default: return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType()) } } // CreateContent creates a new content item func (c *DatabaseClient) CreateContent(siteID, contentID, htmlContent, originalTemplate, lastEditedBy string) (*ContentItem, error) { switch c.database.GetDBType() { case "sqlite3": content, err := c.database.GetSQLiteQueries().CreateContent(context.Background(), sqlite.CreateContentParams{ ID: contentID, SiteID: siteID, HtmlContent: htmlContent, OriginalTemplate: toNullString(originalTemplate), LastEditedBy: lastEditedBy, }) if err != nil { return nil, err } return &ContentItem{ ID: content.ID, SiteID: content.SiteID, HTMLContent: content.HtmlContent, OriginalTemplate: getStringFromNullString(content.OriginalTemplate), LastEditedBy: content.LastEditedBy, }, nil case "postgresql": content, err := c.database.GetPostgreSQLQueries().CreateContent(context.Background(), postgresql.CreateContentParams{ ID: contentID, SiteID: siteID, HtmlContent: htmlContent, OriginalTemplate: toNullString(originalTemplate), LastEditedBy: lastEditedBy, }) if err != nil { return nil, err } return &ContentItem{ ID: content.ID, SiteID: content.SiteID, HTMLContent: content.HtmlContent, OriginalTemplate: getStringFromNullString(content.OriginalTemplate), LastEditedBy: content.LastEditedBy, }, nil default: return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType()) } } // Helper function to convert string to sql.NullString func toNullString(s string) sql.NullString { if s == "" { return sql.NullString{Valid: false} } return sql.NullString{String: s, Valid: true} } // GetCollection retrieves a collection container func (c *DatabaseClient) GetCollection(siteID, collectionID string) (*CollectionItem, error) { switch c.database.GetDBType() { case "sqlite3": collection, err := c.database.GetSQLiteQueries().GetCollection(context.Background(), sqlite.GetCollectionParams{ ID: collectionID, SiteID: siteID, }) if err != nil { return nil, err } return &CollectionItem{ ID: collection.ID, SiteID: collection.SiteID, ContainerHTML: collection.ContainerHtml, LastEditedBy: collection.LastEditedBy, }, nil case "postgresql": collection, err := c.database.GetPostgreSQLQueries().GetCollection(context.Background(), postgresql.GetCollectionParams{ ID: collectionID, SiteID: siteID, }) if err != nil { return nil, err } return &CollectionItem{ ID: collection.ID, SiteID: collection.SiteID, ContainerHTML: collection.ContainerHtml, LastEditedBy: collection.LastEditedBy, }, nil default: return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType()) } } // CreateCollection creates a new collection container func (c *DatabaseClient) CreateCollection(siteID, collectionID, containerHTML, lastEditedBy string) (*CollectionItem, error) { switch c.database.GetDBType() { case "sqlite3": collection, err := c.database.GetSQLiteQueries().CreateCollection(context.Background(), sqlite.CreateCollectionParams{ ID: collectionID, SiteID: siteID, ContainerHtml: containerHTML, LastEditedBy: lastEditedBy, }) if err != nil { return nil, err } return &CollectionItem{ ID: collection.ID, SiteID: collection.SiteID, ContainerHTML: collection.ContainerHtml, LastEditedBy: collection.LastEditedBy, }, nil case "postgresql": collection, err := c.database.GetPostgreSQLQueries().CreateCollection(context.Background(), postgresql.CreateCollectionParams{ ID: collectionID, SiteID: siteID, ContainerHtml: containerHTML, LastEditedBy: lastEditedBy, }) if err != nil { return nil, err } return &CollectionItem{ ID: collection.ID, SiteID: collection.SiteID, ContainerHTML: collection.ContainerHtml, LastEditedBy: collection.LastEditedBy, }, nil default: return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType()) } } // GetCollectionItems retrieves all items in a collection with template information func (c *DatabaseClient) GetCollectionItems(siteID, collectionID string) ([]CollectionItemWithTemplate, error) { switch c.database.GetDBType() { case "sqlite3": items, err := c.database.GetSQLiteQueries().GetCollectionItemsWithTemplate(context.Background(), sqlite.GetCollectionItemsWithTemplateParams{ CollectionID: collectionID, SiteID: siteID, }) if err != nil { return nil, err } result := make([]CollectionItemWithTemplate, len(items)) for i, item := range items { result[i] = CollectionItemWithTemplate{ ItemID: item.ItemID, CollectionID: item.CollectionID, SiteID: item.SiteID, TemplateID: int(item.TemplateID), HTMLContent: item.HtmlContent, Position: int(item.Position), LastEditedBy: item.LastEditedBy, TemplateName: item.TemplateName, HTMLTemplate: item.HtmlTemplate, IsDefault: item.IsDefault != 0, // SQLite uses INTEGER for boolean } } return result, nil case "postgresql": items, err := c.database.GetPostgreSQLQueries().GetCollectionItemsWithTemplate(context.Background(), postgresql.GetCollectionItemsWithTemplateParams{ CollectionID: collectionID, SiteID: siteID, }) if err != nil { return nil, err } result := make([]CollectionItemWithTemplate, len(items)) for i, item := range items { result[i] = CollectionItemWithTemplate{ ItemID: item.ItemID, CollectionID: item.CollectionID, SiteID: item.SiteID, TemplateID: int(item.TemplateID), HTMLContent: item.HtmlContent, Position: int(item.Position), LastEditedBy: item.LastEditedBy, TemplateName: item.TemplateName, HTMLTemplate: item.HtmlTemplate, IsDefault: item.IsDefault, // PostgreSQL uses BOOLEAN } } return result, nil default: return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType()) } } // CreateCollectionTemplate creates a new template for a collection func (c *DatabaseClient) CreateCollectionTemplate(siteID, collectionID, name, htmlTemplate string, isDefault bool) (*CollectionTemplateItem, error) { switch c.database.GetDBType() { case "sqlite3": var isDefaultInt int64 if isDefault { isDefaultInt = 1 } template, err := c.database.GetSQLiteQueries().CreateCollectionTemplate(context.Background(), sqlite.CreateCollectionTemplateParams{ CollectionID: collectionID, SiteID: siteID, Name: name, HtmlTemplate: htmlTemplate, IsDefault: isDefaultInt, }) if err != nil { return nil, err } return &CollectionTemplateItem{ TemplateID: int(template.TemplateID), CollectionID: template.CollectionID, SiteID: template.SiteID, Name: template.Name, HTMLTemplate: template.HtmlTemplate, IsDefault: template.IsDefault != 0, }, nil case "postgresql": template, err := c.database.GetPostgreSQLQueries().CreateCollectionTemplate(context.Background(), postgresql.CreateCollectionTemplateParams{ CollectionID: collectionID, SiteID: siteID, Name: name, HtmlTemplate: htmlTemplate, IsDefault: isDefault, }) if err != nil { return nil, err } return &CollectionTemplateItem{ TemplateID: int(template.TemplateID), CollectionID: template.CollectionID, SiteID: template.SiteID, Name: template.Name, HTMLTemplate: template.HtmlTemplate, IsDefault: template.IsDefault, }, nil default: return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType()) } } // GetCollectionTemplates retrieves all templates for a collection func (c *DatabaseClient) GetCollectionTemplates(siteID, collectionID string) ([]CollectionTemplateItem, error) { switch c.database.GetDBType() { case "sqlite3": templates, err := c.database.GetSQLiteQueries().GetCollectionTemplates(context.Background(), sqlite.GetCollectionTemplatesParams{ CollectionID: collectionID, SiteID: siteID, }) if err != nil { return nil, err } result := make([]CollectionTemplateItem, len(templates)) for i, template := range templates { result[i] = CollectionTemplateItem{ TemplateID: int(template.TemplateID), CollectionID: template.CollectionID, SiteID: template.SiteID, Name: template.Name, HTMLTemplate: template.HtmlTemplate, IsDefault: template.IsDefault != 0, // SQLite uses INTEGER for boolean } } return result, nil case "postgresql": templates, err := c.database.GetPostgreSQLQueries().GetCollectionTemplates(context.Background(), postgresql.GetCollectionTemplatesParams{ CollectionID: collectionID, SiteID: siteID, }) if err != nil { return nil, err } result := make([]CollectionTemplateItem, len(templates)) for i, template := range templates { result[i] = CollectionTemplateItem{ TemplateID: int(template.TemplateID), CollectionID: template.CollectionID, SiteID: template.SiteID, Name: template.Name, HTMLTemplate: template.HtmlTemplate, IsDefault: template.IsDefault, // PostgreSQL uses BOOLEAN } } return result, nil default: return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType()) } } // CreateCollectionItem creates a new collection item func (c *DatabaseClient) CreateCollectionItem(siteID, collectionID, itemID string, templateID int, htmlContent string, position int, lastEditedBy string) (*CollectionItemWithTemplate, error) { switch c.database.GetDBType() { case "sqlite3": item, err := c.database.GetSQLiteQueries().CreateCollectionItem(context.Background(), sqlite.CreateCollectionItemParams{ ItemID: itemID, CollectionID: collectionID, SiteID: siteID, TemplateID: int64(templateID), HtmlContent: htmlContent, Position: int64(position), LastEditedBy: lastEditedBy, }) if err != nil { return nil, err } return &CollectionItemWithTemplate{ ItemID: item.ItemID, CollectionID: item.CollectionID, SiteID: item.SiteID, TemplateID: int(item.TemplateID), HTMLContent: item.HtmlContent, Position: int(item.Position), LastEditedBy: item.LastEditedBy, }, nil case "postgresql": item, err := c.database.GetPostgreSQLQueries().CreateCollectionItem(context.Background(), postgresql.CreateCollectionItemParams{ ItemID: itemID, CollectionID: collectionID, SiteID: siteID, TemplateID: int32(templateID), HtmlContent: htmlContent, Position: int32(position), LastEditedBy: lastEditedBy, }) if err != nil { return nil, err } return &CollectionItemWithTemplate{ ItemID: item.ItemID, CollectionID: item.CollectionID, SiteID: item.SiteID, TemplateID: int(item.TemplateID), HTMLContent: item.HtmlContent, Position: int(item.Position), LastEditedBy: item.LastEditedBy, }, nil default: return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType()) } } // CreateCollectionItemAtomic creates a collection item with all its content entries atomically func (c *DatabaseClient) CreateCollectionItemAtomic( siteID, collectionID string, templateID int, lastEditedBy string, ) (*CollectionItemWithTemplate, error) { // Get template HTML for processing templates, err := c.GetCollectionTemplates(siteID, collectionID) if err != nil { return nil, fmt.Errorf("failed to get templates: %w", err) } var templateHTML string for _, template := range templates { if template.TemplateID == templateID { templateHTML = template.HTMLTemplate break } } if templateHTML == "" { return nil, fmt.Errorf("template %d not found", templateID) } // Use unified engine approach (no more TemplateProcessor) engine := NewContentEngine(c) // Create collection item using unified engine method return engine.CreateCollectionItemFromTemplate( siteID, collectionID, templateID, templateHTML, lastEditedBy, ) }