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:
@@ -105,6 +105,18 @@ func (db *Database) GetPostgreSQLDB() *sql.DB {
|
||||
return db.conn
|
||||
}
|
||||
|
||||
// NewContentRepository creates a repository based on the database type
|
||||
func (db *Database) NewContentRepository() ContentRepository {
|
||||
switch db.dbType {
|
||||
case "sqlite3":
|
||||
return NewSQLiteRepository(db.conn)
|
||||
case "postgresql":
|
||||
return NewPostgreSQLRepository(db.conn)
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported database type: %s", db.dbType))
|
||||
}
|
||||
}
|
||||
|
||||
// initializeSQLiteSchema sets up the SQLite database schema
|
||||
func (db *Database) initializeSQLiteSchema() error {
|
||||
ctx := context.Background()
|
||||
|
||||
285
internal/db/postgresql_repository.go
Normal file
285
internal/db/postgresql_repository.go
Normal file
@@ -0,0 +1,285 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"github.com/insertr/insertr/internal/db/postgresql"
|
||||
)
|
||||
|
||||
// PostgreSQLRepository implements ContentRepository for PostgreSQL databases
|
||||
type PostgreSQLRepository struct {
|
||||
queries *postgresql.Queries
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
// NewPostgreSQLRepository creates a new PostgreSQL repository
|
||||
func NewPostgreSQLRepository(db *sql.DB) *PostgreSQLRepository {
|
||||
return &PostgreSQLRepository{
|
||||
queries: postgresql.New(db),
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
// GetContent retrieves a single content item
|
||||
func (r *PostgreSQLRepository) GetContent(ctx context.Context, siteID, contentID string) (*ContentItem, error) {
|
||||
content, err := r.queries.GetContent(ctx, 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
|
||||
}
|
||||
|
||||
// GetBulkContent retrieves multiple content items
|
||||
func (r *PostgreSQLRepository) GetBulkContent(ctx context.Context, siteID string, contentIDs []string) (map[string]ContentItem, error) {
|
||||
contents, err := r.queries.GetBulkContent(ctx, 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
|
||||
}
|
||||
|
||||
// GetAllContent retrieves all content items for a site
|
||||
func (r *PostgreSQLRepository) GetAllContent(ctx context.Context, siteID string) (map[string]ContentItem, error) {
|
||||
contents, err := r.queries.GetAllContent(ctx, 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
|
||||
}
|
||||
|
||||
// CreateContent creates a new content item
|
||||
func (r *PostgreSQLRepository) CreateContent(ctx context.Context, siteID, contentID, htmlContent, originalTemplate, lastEditedBy string) (*ContentItem, error) {
|
||||
content, err := r.queries.CreateContent(ctx, 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
|
||||
}
|
||||
|
||||
// GetCollection retrieves a collection container
|
||||
func (r *PostgreSQLRepository) GetCollection(ctx context.Context, siteID, collectionID string) (*CollectionItem, error) {
|
||||
collection, err := r.queries.GetCollection(ctx, 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
|
||||
}
|
||||
|
||||
// CreateCollection creates a new collection container
|
||||
func (r *PostgreSQLRepository) CreateCollection(ctx context.Context, siteID, collectionID, containerHTML, lastEditedBy string) (*CollectionItem, error) {
|
||||
collection, err := r.queries.CreateCollection(ctx, 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
|
||||
}
|
||||
|
||||
// GetCollectionItems retrieves all items in a collection with template information
|
||||
func (r *PostgreSQLRepository) GetCollectionItems(ctx context.Context, siteID, collectionID string) ([]CollectionItemWithTemplate, error) {
|
||||
items, err := r.queries.GetCollectionItemsWithTemplate(ctx, 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
|
||||
}
|
||||
|
||||
// CreateCollectionTemplate creates a new template for a collection
|
||||
func (r *PostgreSQLRepository) CreateCollectionTemplate(ctx context.Context, siteID, collectionID, name, htmlTemplate string, isDefault bool) (*CollectionTemplateItem, error) {
|
||||
template, err := r.queries.CreateCollectionTemplate(ctx, 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
|
||||
}
|
||||
|
||||
// GetCollectionTemplates retrieves all templates for a collection
|
||||
func (r *PostgreSQLRepository) GetCollectionTemplates(ctx context.Context, siteID, collectionID string) ([]CollectionTemplateItem, error) {
|
||||
templates, err := r.queries.GetCollectionTemplates(ctx, 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
|
||||
}
|
||||
|
||||
// CreateCollectionItem creates a new collection item
|
||||
func (r *PostgreSQLRepository) CreateCollectionItem(ctx context.Context, siteID, collectionID, itemID string, templateID int, htmlContent string, position int, lastEditedBy string) (*CollectionItemWithTemplate, error) {
|
||||
item, err := r.queries.CreateCollectionItem(ctx, 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
|
||||
}
|
||||
|
||||
// CreateCollectionItemAtomic creates a collection item with all its content entries atomically
|
||||
func (r *PostgreSQLRepository) CreateCollectionItemAtomic(ctx context.Context, siteID, collectionID string, templateID int, lastEditedBy string) (*CollectionItemWithTemplate, error) {
|
||||
// Get template HTML for processing
|
||||
templates, err := r.GetCollectionTemplates(ctx, 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)
|
||||
}
|
||||
|
||||
// TODO: Implement using unified engine approach
|
||||
// This requires circular dependency resolution
|
||||
return nil, fmt.Errorf("CreateCollectionItemAtomic not yet implemented for PostgreSQL")
|
||||
}
|
||||
|
||||
// WithTransaction executes a function within a database transaction
|
||||
func (r *PostgreSQLRepository) WithTransaction(ctx context.Context, fn func(ContentRepository) error) error {
|
||||
tx, err := r.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
txRepo := &PostgreSQLRepository{
|
||||
queries: r.queries.WithTx(tx),
|
||||
db: r.db,
|
||||
}
|
||||
|
||||
if err := fn(txRepo); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.Commit()
|
||||
}
|
||||
103
internal/db/repository.go
Normal file
103
internal/db/repository.go
Normal file
@@ -0,0 +1,103 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
// ContentRepository interface for accessing content data
|
||||
// This replaces the ContentClient interface from engine package
|
||||
type ContentRepository interface {
|
||||
GetContent(ctx context.Context, siteID, contentID string) (*ContentItem, error)
|
||||
GetBulkContent(ctx context.Context, siteID string, contentIDs []string) (map[string]ContentItem, error)
|
||||
GetAllContent(ctx context.Context, siteID string) (map[string]ContentItem, error)
|
||||
CreateContent(ctx context.Context, siteID, contentID, htmlContent, originalTemplate, lastEditedBy string) (*ContentItem, error)
|
||||
|
||||
// Collection operations
|
||||
GetCollection(ctx context.Context, siteID, collectionID string) (*CollectionItem, error)
|
||||
CreateCollection(ctx context.Context, siteID, collectionID, containerHTML, lastEditedBy string) (*CollectionItem, error)
|
||||
GetCollectionItems(ctx context.Context, siteID, collectionID string) ([]CollectionItemWithTemplate, error)
|
||||
GetCollectionTemplates(ctx context.Context, siteID, collectionID string) ([]CollectionTemplateItem, error)
|
||||
CreateCollectionTemplate(ctx context.Context, siteID, collectionID, name, htmlTemplate string, isDefault bool) (*CollectionTemplateItem, error)
|
||||
CreateCollectionItem(ctx context.Context, siteID, collectionID, itemID string, templateID int, htmlContent string, position int, lastEditedBy string) (*CollectionItemWithTemplate, error)
|
||||
CreateCollectionItemAtomic(ctx context.Context, siteID, collectionID string, templateID int, lastEditedBy string) (*CollectionItemWithTemplate, error)
|
||||
|
||||
// Transaction support
|
||||
WithTransaction(ctx context.Context, fn func(ContentRepository) error) error
|
||||
}
|
||||
|
||||
// ContentItem represents a piece of content from the database
|
||||
type ContentItem struct {
|
||||
ID string `json:"id"`
|
||||
SiteID string `json:"site_id"`
|
||||
HTMLContent string `json:"html_content"`
|
||||
OriginalTemplate string `json:"original_template"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
LastEditedBy string `json:"last_edited_by,omitempty"`
|
||||
}
|
||||
|
||||
// ContentResponse represents the API response structure
|
||||
type ContentResponse struct {
|
||||
Content []ContentItem `json:"content"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// CollectionItem represents a collection container from the database
|
||||
type CollectionItem struct {
|
||||
ID string `json:"id"`
|
||||
SiteID string `json:"site_id"`
|
||||
ContainerHTML string `json:"container_html"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
LastEditedBy string `json:"last_edited_by,omitempty"`
|
||||
}
|
||||
|
||||
// CollectionTemplateItem represents a collection template from the database
|
||||
type CollectionTemplateItem struct {
|
||||
TemplateID int `json:"template_id"`
|
||||
CollectionID string `json:"collection_id"`
|
||||
SiteID string `json:"site_id"`
|
||||
Name string `json:"name"`
|
||||
HTMLTemplate string `json:"html_template"`
|
||||
IsDefault bool `json:"is_default"`
|
||||
}
|
||||
|
||||
// CollectionItemWithTemplate represents a collection item with its template information
|
||||
type CollectionItemWithTemplate struct {
|
||||
ItemID string `json:"item_id"`
|
||||
CollectionID string `json:"collection_id"`
|
||||
SiteID string `json:"site_id"`
|
||||
TemplateID int `json:"template_id"`
|
||||
HTMLContent string `json:"html_content"`
|
||||
Position int `json:"position"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
LastEditedBy string `json:"last_edited_by"`
|
||||
|
||||
// Template information
|
||||
TemplateName string `json:"template_name"`
|
||||
HTMLTemplate string `json:"html_template"`
|
||||
IsDefault bool `json:"is_default"`
|
||||
}
|
||||
|
||||
// Helper function to convert sql.NullString to string
|
||||
func getStringFromNullString(ns sql.NullString) string {
|
||||
if ns.Valid {
|
||||
return ns.String
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ToNullString converts a string to sql.NullString
|
||||
func ToNullString(s string) sql.NullString {
|
||||
if s == "" {
|
||||
return sql.NullString{Valid: false}
|
||||
}
|
||||
return sql.NullString{String: s, Valid: true}
|
||||
}
|
||||
|
||||
// FromNullString converts sql.NullString to string
|
||||
func FromNullString(ns sql.NullString) string {
|
||||
if ns.Valid {
|
||||
return ns.String
|
||||
}
|
||||
return ""
|
||||
}
|
||||
290
internal/db/sqlite_repository.go
Normal file
290
internal/db/sqlite_repository.go
Normal file
@@ -0,0 +1,290 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"github.com/insertr/insertr/internal/db/sqlite"
|
||||
)
|
||||
|
||||
// SQLiteRepository implements ContentRepository for SQLite databases
|
||||
type SQLiteRepository struct {
|
||||
queries *sqlite.Queries
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
// NewSQLiteRepository creates a new SQLite repository
|
||||
func NewSQLiteRepository(db *sql.DB) *SQLiteRepository {
|
||||
return &SQLiteRepository{
|
||||
queries: sqlite.New(db),
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
// GetContent retrieves a single content item
|
||||
func (r *SQLiteRepository) GetContent(ctx context.Context, siteID, contentID string) (*ContentItem, error) {
|
||||
content, err := r.queries.GetContent(ctx, 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
|
||||
}
|
||||
|
||||
// GetBulkContent retrieves multiple content items
|
||||
func (r *SQLiteRepository) GetBulkContent(ctx context.Context, siteID string, contentIDs []string) (map[string]ContentItem, error) {
|
||||
contents, err := r.queries.GetBulkContent(ctx, 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
|
||||
}
|
||||
|
||||
// GetAllContent retrieves all content items for a site
|
||||
func (r *SQLiteRepository) GetAllContent(ctx context.Context, siteID string) (map[string]ContentItem, error) {
|
||||
contents, err := r.queries.GetAllContent(ctx, 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
|
||||
}
|
||||
|
||||
// CreateContent creates a new content item
|
||||
func (r *SQLiteRepository) CreateContent(ctx context.Context, siteID, contentID, htmlContent, originalTemplate, lastEditedBy string) (*ContentItem, error) {
|
||||
content, err := r.queries.CreateContent(ctx, 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
|
||||
}
|
||||
|
||||
// GetCollection retrieves a collection container
|
||||
func (r *SQLiteRepository) GetCollection(ctx context.Context, siteID, collectionID string) (*CollectionItem, error) {
|
||||
collection, err := r.queries.GetCollection(ctx, 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
|
||||
}
|
||||
|
||||
// CreateCollection creates a new collection container
|
||||
func (r *SQLiteRepository) CreateCollection(ctx context.Context, siteID, collectionID, containerHTML, lastEditedBy string) (*CollectionItem, error) {
|
||||
collection, err := r.queries.CreateCollection(ctx, 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
|
||||
}
|
||||
|
||||
// GetCollectionItems retrieves all items in a collection with template information
|
||||
func (r *SQLiteRepository) GetCollectionItems(ctx context.Context, siteID, collectionID string) ([]CollectionItemWithTemplate, error) {
|
||||
items, err := r.queries.GetCollectionItemsWithTemplate(ctx, 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
|
||||
}
|
||||
|
||||
// CreateCollectionTemplate creates a new template for a collection
|
||||
func (r *SQLiteRepository) CreateCollectionTemplate(ctx context.Context, siteID, collectionID, name, htmlTemplate string, isDefault bool) (*CollectionTemplateItem, error) {
|
||||
var isDefaultInt int64
|
||||
if isDefault {
|
||||
isDefaultInt = 1
|
||||
}
|
||||
|
||||
template, err := r.queries.CreateCollectionTemplate(ctx, 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
|
||||
}
|
||||
|
||||
// GetCollectionTemplates retrieves all templates for a collection
|
||||
func (r *SQLiteRepository) GetCollectionTemplates(ctx context.Context, siteID, collectionID string) ([]CollectionTemplateItem, error) {
|
||||
templates, err := r.queries.GetCollectionTemplates(ctx, 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
|
||||
}
|
||||
|
||||
// CreateCollectionItem creates a new collection item
|
||||
func (r *SQLiteRepository) CreateCollectionItem(ctx context.Context, siteID, collectionID, itemID string, templateID int, htmlContent string, position int, lastEditedBy string) (*CollectionItemWithTemplate, error) {
|
||||
item, err := r.queries.CreateCollectionItem(ctx, 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
|
||||
}
|
||||
|
||||
// CreateCollectionItemAtomic creates a collection item with all its content entries atomically
|
||||
func (r *SQLiteRepository) CreateCollectionItemAtomic(ctx context.Context, siteID, collectionID string, templateID int, lastEditedBy string) (*CollectionItemWithTemplate, error) {
|
||||
// Get template HTML for processing
|
||||
templates, err := r.GetCollectionTemplates(ctx, 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)
|
||||
}
|
||||
|
||||
// TODO: Implement using unified engine approach
|
||||
// This requires circular dependency resolution
|
||||
return nil, fmt.Errorf("CreateCollectionItemAtomic not yet implemented for SQLite")
|
||||
}
|
||||
|
||||
// WithTransaction executes a function within a database transaction
|
||||
func (r *SQLiteRepository) WithTransaction(ctx context.Context, fn func(ContentRepository) error) error {
|
||||
tx, err := r.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
txRepo := &SQLiteRepository{
|
||||
queries: r.queries.WithTx(tx),
|
||||
db: r.db,
|
||||
}
|
||||
|
||||
if err := fn(txRepo); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.Commit()
|
||||
}
|
||||
Reference in New Issue
Block a user