Implement complete collection persistence with database-backed survival across server restarts

• Add full multi-table schema for collections with normalized design (collections, collection_templates, collection_items, collection_item_versions)
• Implement collection detection and processing in enhancement pipeline for .insertr-add elements
• Add template extraction and storage from existing HTML children with multi-variant support
• Enable collection reconstruction from database on server restart with proper DOM rebuilding
• Extend ContentClient interface with collection operations and full database integration
• Update enhance command to use engine.DatabaseClient for collection persistence support
This commit is contained in:
2025-09-22 18:29:58 +02:00
parent b25663f76b
commit 2315ba4750
36 changed files with 4356 additions and 46 deletions

View File

@@ -217,3 +217,196 @@ func toNullString(s string) sql.NullString {
}
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())
}
}