- Remove mock_content setting (working database loop makes it unnecessary) - Change server.dev_mode to global dev_mode setting for consistency - Update CLI to use cli.site_id and cli.output for scoped configuration - Implement database client for CLI enhance command (complete static site loop) - Update justfile to use INSERTR_DATABASE_PATH environment variable - Enable multi-site architecture: server is site-agnostic, CLI is site-specific - Unified insertr.yaml now supports both server and CLI with minimal config
173 lines
4.4 KiB
Go
173 lines
4.4 KiB
Go
package content
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/insertr/insertr/internal/db"
|
|
"github.com/insertr/insertr/internal/db/postgresql"
|
|
"github.com/insertr/insertr/internal/db/sqlite"
|
|
)
|
|
|
|
// DatabaseClient implements ContentClient for direct database access
|
|
type DatabaseClient struct {
|
|
db *db.Database
|
|
}
|
|
|
|
// NewDatabaseClient creates a new database content client
|
|
func NewDatabaseClient(database *db.Database) *DatabaseClient {
|
|
return &DatabaseClient{
|
|
db: database,
|
|
}
|
|
}
|
|
|
|
// GetContent fetches a single content item by ID
|
|
func (d *DatabaseClient) GetContent(siteID, contentID string) (*ContentItem, error) {
|
|
ctx := context.Background()
|
|
var content interface{}
|
|
var err error
|
|
|
|
switch d.db.GetDBType() {
|
|
case "sqlite3":
|
|
content, err = d.db.GetSQLiteQueries().GetContent(ctx, sqlite.GetContentParams{
|
|
ID: contentID,
|
|
SiteID: siteID,
|
|
})
|
|
case "postgresql":
|
|
content, err = d.db.GetPostgreSQLQueries().GetContent(ctx, postgresql.GetContentParams{
|
|
ID: contentID,
|
|
SiteID: siteID,
|
|
})
|
|
default:
|
|
return nil, fmt.Errorf("unsupported database type: %s", d.db.GetDBType())
|
|
}
|
|
|
|
if err != nil {
|
|
if err == sql.ErrNoRows {
|
|
return nil, nil // Content not found, return nil without error
|
|
}
|
|
return nil, fmt.Errorf("database error: %w", err)
|
|
}
|
|
|
|
item := d.convertToContentItem(content)
|
|
return &item, nil
|
|
}
|
|
|
|
// GetBulkContent fetches multiple content items by IDs
|
|
func (d *DatabaseClient) GetBulkContent(siteID string, contentIDs []string) (map[string]ContentItem, error) {
|
|
if len(contentIDs) == 0 {
|
|
return make(map[string]ContentItem), nil
|
|
}
|
|
|
|
ctx := context.Background()
|
|
var dbContent interface{}
|
|
var err error
|
|
|
|
switch d.db.GetDBType() {
|
|
case "sqlite3":
|
|
dbContent, err = d.db.GetSQLiteQueries().GetBulkContent(ctx, sqlite.GetBulkContentParams{
|
|
SiteID: siteID,
|
|
Ids: contentIDs,
|
|
})
|
|
case "postgresql":
|
|
dbContent, err = d.db.GetPostgreSQLQueries().GetBulkContent(ctx, postgresql.GetBulkContentParams{
|
|
SiteID: siteID,
|
|
Ids: contentIDs,
|
|
})
|
|
default:
|
|
return nil, fmt.Errorf("unsupported database type: %s", d.db.GetDBType())
|
|
}
|
|
|
|
if err != nil {
|
|
return nil, fmt.Errorf("database error: %w", err)
|
|
}
|
|
|
|
items := d.convertToContentItemList(dbContent)
|
|
|
|
// Convert slice to map for easy lookup
|
|
result := make(map[string]ContentItem)
|
|
for _, item := range items {
|
|
result[item.ID] = item
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// GetAllContent fetches all content for a site
|
|
func (d *DatabaseClient) GetAllContent(siteID string) (map[string]ContentItem, error) {
|
|
ctx := context.Background()
|
|
var dbContent interface{}
|
|
var err error
|
|
|
|
switch d.db.GetDBType() {
|
|
case "sqlite3":
|
|
dbContent, err = d.db.GetSQLiteQueries().GetAllContent(ctx, siteID)
|
|
case "postgresql":
|
|
dbContent, err = d.db.GetPostgreSQLQueries().GetAllContent(ctx, siteID)
|
|
default:
|
|
return nil, fmt.Errorf("unsupported database type: %s", d.db.GetDBType())
|
|
}
|
|
|
|
if err != nil {
|
|
return nil, fmt.Errorf("database error: %w", err)
|
|
}
|
|
|
|
items := d.convertToContentItemList(dbContent)
|
|
|
|
// Convert slice to map for easy lookup
|
|
result := make(map[string]ContentItem)
|
|
for _, item := range items {
|
|
result[item.ID] = item
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// convertToContentItem converts database models to content.ContentItem
|
|
func (d *DatabaseClient) convertToContentItem(content interface{}) ContentItem {
|
|
switch d.db.GetDBType() {
|
|
case "sqlite3":
|
|
c := content.(sqlite.Content)
|
|
return ContentItem{
|
|
ID: c.ID,
|
|
SiteID: c.SiteID,
|
|
Value: c.Value,
|
|
Type: c.Type,
|
|
UpdatedAt: time.Unix(c.UpdatedAt, 0).Format(time.RFC3339),
|
|
}
|
|
case "postgresql":
|
|
c := content.(postgresql.Content)
|
|
return ContentItem{
|
|
ID: c.ID,
|
|
SiteID: c.SiteID,
|
|
Value: c.Value,
|
|
Type: c.Type,
|
|
UpdatedAt: time.Unix(c.UpdatedAt, 0).Format(time.RFC3339),
|
|
}
|
|
}
|
|
return ContentItem{} // Should never happen
|
|
}
|
|
|
|
// convertToContentItemList converts database model lists to content.ContentItem slice
|
|
func (d *DatabaseClient) convertToContentItemList(contentList interface{}) []ContentItem {
|
|
switch d.db.GetDBType() {
|
|
case "sqlite3":
|
|
list := contentList.([]sqlite.Content)
|
|
items := make([]ContentItem, len(list))
|
|
for i, content := range list {
|
|
items[i] = d.convertToContentItem(content)
|
|
}
|
|
return items
|
|
case "postgresql":
|
|
list := contentList.([]postgresql.Content)
|
|
items := make([]ContentItem, len(list))
|
|
for i, content := range list {
|
|
items[i] = d.convertToContentItem(content)
|
|
}
|
|
return items
|
|
}
|
|
return []ContentItem{} // Should never happen
|
|
}
|