Initial commit: Open sourcing all of the Maple Open Technologies code.
This commit is contained in:
commit
755d54a99d
2010 changed files with 448675 additions and 0 deletions
279
cloud/maplepress-backend/internal/repo/page_repo.go
Normal file
279
cloud/maplepress-backend/internal/repo/page_repo.go
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
// File Path: monorepo/cloud/maplepress-backend/internal/repo/page_repo.go
|
||||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/domain/page"
|
||||
)
|
||||
|
||||
type pageRepository struct {
|
||||
session *gocql.Session
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
func NewPageRepository(session *gocql.Session, logger *zap.Logger) page.Repository {
|
||||
return &pageRepository{
|
||||
session: session,
|
||||
logger: logger.Named("page-repo"),
|
||||
}
|
||||
}
|
||||
|
||||
// Create inserts a new page
|
||||
func (r *pageRepository) Create(ctx context.Context, p *page.Page) error {
|
||||
query := `
|
||||
INSERT INTO maplepress.pages_by_site (
|
||||
site_id, page_id, tenant_id,
|
||||
title, content, excerpt, url,
|
||||
status, post_type, author,
|
||||
published_at, modified_at, indexed_at,
|
||||
meilisearch_doc_id,
|
||||
created_at, updated_at,
|
||||
created_from_ip_address, created_from_ip_timestamp,
|
||||
modified_from_ip_address, modified_from_ip_timestamp
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`
|
||||
|
||||
return r.session.Query(query,
|
||||
p.SiteID, p.PageID, p.TenantID,
|
||||
p.Title, p.Content, p.Excerpt, p.URL,
|
||||
p.Status, p.PostType, p.Author,
|
||||
p.PublishedAt, p.ModifiedAt, p.IndexedAt,
|
||||
p.MeilisearchDocID,
|
||||
p.CreatedAt, p.UpdatedAt,
|
||||
p.CreatedFromIPAddress, p.CreatedFromIPTimestamp,
|
||||
p.ModifiedFromIPAddress, p.ModifiedFromIPTimestamp,
|
||||
).WithContext(ctx).Exec()
|
||||
}
|
||||
|
||||
// Update updates an existing page
|
||||
func (r *pageRepository) Update(ctx context.Context, p *page.Page) error {
|
||||
query := `
|
||||
UPDATE maplepress.pages_by_site SET
|
||||
title = ?,
|
||||
content = ?,
|
||||
excerpt = ?,
|
||||
url = ?,
|
||||
status = ?,
|
||||
post_type = ?,
|
||||
author = ?,
|
||||
published_at = ?,
|
||||
modified_at = ?,
|
||||
indexed_at = ?,
|
||||
meilisearch_doc_id = ?,
|
||||
updated_at = ?,
|
||||
modified_from_ip_address = ?,
|
||||
modified_from_ip_timestamp = ?
|
||||
WHERE site_id = ? AND page_id = ?
|
||||
`
|
||||
|
||||
return r.session.Query(query,
|
||||
p.Title, p.Content, p.Excerpt, p.URL,
|
||||
p.Status, p.PostType, p.Author,
|
||||
p.PublishedAt, p.ModifiedAt, p.IndexedAt,
|
||||
p.MeilisearchDocID,
|
||||
p.UpdatedAt,
|
||||
p.ModifiedFromIPAddress, p.ModifiedFromIPTimestamp,
|
||||
p.SiteID, p.PageID,
|
||||
).WithContext(ctx).Exec()
|
||||
}
|
||||
|
||||
// Upsert creates or updates a page
|
||||
func (r *pageRepository) Upsert(ctx context.Context, p *page.Page) error {
|
||||
// In Cassandra, INSERT acts as an upsert
|
||||
return r.Create(ctx, p)
|
||||
}
|
||||
|
||||
// GetByID retrieves a page by site_id and page_id
|
||||
func (r *pageRepository) GetByID(ctx context.Context, siteID gocql.UUID, pageID string) (*page.Page, error) {
|
||||
query := `
|
||||
SELECT site_id, page_id, tenant_id,
|
||||
title, content, excerpt, url,
|
||||
status, post_type, author,
|
||||
published_at, modified_at, indexed_at,
|
||||
meilisearch_doc_id,
|
||||
created_at, updated_at,
|
||||
created_from_ip_address, created_from_ip_timestamp,
|
||||
modified_from_ip_address, modified_from_ip_timestamp
|
||||
FROM maplepress.pages_by_site
|
||||
WHERE site_id = ? AND page_id = ?
|
||||
`
|
||||
|
||||
p := &page.Page{}
|
||||
err := r.session.Query(query, siteID, pageID).
|
||||
WithContext(ctx).
|
||||
Scan(
|
||||
&p.SiteID, &p.PageID, &p.TenantID,
|
||||
&p.Title, &p.Content, &p.Excerpt, &p.URL,
|
||||
&p.Status, &p.PostType, &p.Author,
|
||||
&p.PublishedAt, &p.ModifiedAt, &p.IndexedAt,
|
||||
&p.MeilisearchDocID,
|
||||
&p.CreatedAt, &p.UpdatedAt,
|
||||
&p.CreatedFromIPAddress, &p.CreatedFromIPTimestamp,
|
||||
&p.ModifiedFromIPAddress, &p.ModifiedFromIPTimestamp,
|
||||
)
|
||||
|
||||
if err == gocql.ErrNotFound {
|
||||
return nil, fmt.Errorf("page not found: site_id=%s, page_id=%s", siteID, pageID)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get page: %w", err)
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// GetBySiteID retrieves all pages for a site
|
||||
func (r *pageRepository) GetBySiteID(ctx context.Context, siteID gocql.UUID) ([]*page.Page, error) {
|
||||
query := `
|
||||
SELECT site_id, page_id, tenant_id,
|
||||
title, content, excerpt, url,
|
||||
status, post_type, author,
|
||||
published_at, modified_at, indexed_at,
|
||||
meilisearch_doc_id,
|
||||
created_at, updated_at,
|
||||
created_from_ip_address, created_from_ip_timestamp,
|
||||
modified_from_ip_address, modified_from_ip_timestamp
|
||||
FROM maplepress.pages_by_site
|
||||
WHERE site_id = ?
|
||||
`
|
||||
|
||||
iter := r.session.Query(query, siteID).WithContext(ctx).Iter()
|
||||
defer iter.Close()
|
||||
|
||||
var pages []*page.Page
|
||||
p := &page.Page{}
|
||||
|
||||
for iter.Scan(
|
||||
&p.SiteID, &p.PageID, &p.TenantID,
|
||||
&p.Title, &p.Content, &p.Excerpt, &p.URL,
|
||||
&p.Status, &p.PostType, &p.Author,
|
||||
&p.PublishedAt, &p.ModifiedAt, &p.IndexedAt,
|
||||
&p.MeilisearchDocID,
|
||||
&p.CreatedAt, &p.UpdatedAt,
|
||||
&p.CreatedFromIPAddress, &p.CreatedFromIPTimestamp,
|
||||
&p.ModifiedFromIPAddress, &p.ModifiedFromIPTimestamp,
|
||||
) {
|
||||
pages = append(pages, p)
|
||||
p = &page.Page{} // Create new instance for next iteration
|
||||
}
|
||||
|
||||
if err := iter.Close(); err != nil {
|
||||
return nil, fmt.Errorf("failed to iterate pages: %w", err)
|
||||
}
|
||||
|
||||
return pages, nil
|
||||
}
|
||||
|
||||
// GetBySiteIDPaginated retrieves pages for a site with pagination
|
||||
func (r *pageRepository) GetBySiteIDPaginated(ctx context.Context, siteID gocql.UUID, limit int, pageState []byte) ([]*page.Page, []byte, error) {
|
||||
query := `
|
||||
SELECT site_id, page_id, tenant_id,
|
||||
title, content, excerpt, url,
|
||||
status, post_type, author,
|
||||
published_at, modified_at, indexed_at,
|
||||
meilisearch_doc_id,
|
||||
created_at, updated_at,
|
||||
created_from_ip_address, created_from_ip_timestamp,
|
||||
modified_from_ip_address, modified_from_ip_timestamp
|
||||
FROM maplepress.pages_by_site
|
||||
WHERE site_id = ?
|
||||
`
|
||||
|
||||
q := r.session.Query(query, siteID).WithContext(ctx).PageSize(limit)
|
||||
|
||||
if len(pageState) > 0 {
|
||||
q = q.PageState(pageState)
|
||||
}
|
||||
|
||||
iter := q.Iter()
|
||||
defer iter.Close()
|
||||
|
||||
var pages []*page.Page
|
||||
p := &page.Page{}
|
||||
|
||||
for iter.Scan(
|
||||
&p.SiteID, &p.PageID, &p.TenantID,
|
||||
&p.Title, &p.Content, &p.Excerpt, &p.URL,
|
||||
&p.Status, &p.PostType, &p.Author,
|
||||
&p.PublishedAt, &p.ModifiedAt, &p.IndexedAt,
|
||||
&p.MeilisearchDocID,
|
||||
&p.CreatedAt, &p.UpdatedAt,
|
||||
&p.CreatedFromIPAddress, &p.CreatedFromIPTimestamp,
|
||||
&p.ModifiedFromIPAddress, &p.ModifiedFromIPTimestamp,
|
||||
) {
|
||||
pages = append(pages, p)
|
||||
p = &page.Page{} // Create new instance for next iteration
|
||||
}
|
||||
|
||||
if err := iter.Close(); err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to iterate pages: %w", err)
|
||||
}
|
||||
|
||||
nextPageState := iter.PageState()
|
||||
return pages, nextPageState, nil
|
||||
}
|
||||
|
||||
// Delete deletes a page
|
||||
func (r *pageRepository) Delete(ctx context.Context, siteID gocql.UUID, pageID string) error {
|
||||
query := `DELETE FROM maplepress.pages_by_site WHERE site_id = ? AND page_id = ?`
|
||||
return r.session.Query(query, siteID, pageID).WithContext(ctx).Exec()
|
||||
}
|
||||
|
||||
// DeleteBySiteID deletes all pages for a site
|
||||
func (r *pageRepository) DeleteBySiteID(ctx context.Context, siteID gocql.UUID) error {
|
||||
// Note: This is an expensive operation in Cassandra
|
||||
// Better to delete partition by partition if possible
|
||||
query := `DELETE FROM maplepress.pages_by_site WHERE site_id = ?`
|
||||
return r.session.Query(query, siteID).WithContext(ctx).Exec()
|
||||
}
|
||||
|
||||
// DeleteMultiple deletes multiple pages by their IDs
|
||||
func (r *pageRepository) DeleteMultiple(ctx context.Context, siteID gocql.UUID, pageIDs []string) error {
|
||||
// Use batch for efficiency
|
||||
batch := r.session.NewBatch(gocql.LoggedBatch).WithContext(ctx)
|
||||
|
||||
query := `DELETE FROM maplepress.pages_by_site WHERE site_id = ? AND page_id = ?`
|
||||
|
||||
for _, pageID := range pageIDs {
|
||||
batch.Query(query, siteID, pageID)
|
||||
}
|
||||
|
||||
return r.session.ExecuteBatch(batch)
|
||||
}
|
||||
|
||||
// CountBySiteID counts pages for a site
|
||||
func (r *pageRepository) CountBySiteID(ctx context.Context, siteID gocql.UUID) (int64, error) {
|
||||
query := `SELECT COUNT(*) FROM maplepress.pages_by_site WHERE site_id = ?`
|
||||
|
||||
var count int64
|
||||
err := r.session.Query(query, siteID).WithContext(ctx).Scan(&count)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to count pages: %w", err)
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// Exists checks if a page exists
|
||||
func (r *pageRepository) Exists(ctx context.Context, siteID gocql.UUID, pageID string) (bool, error) {
|
||||
query := `SELECT page_id FROM maplepress.pages_by_site WHERE site_id = ? AND page_id = ?`
|
||||
|
||||
var id string
|
||||
err := r.session.Query(query, siteID, pageID).WithContext(ctx).Scan(&id)
|
||||
|
||||
if err == gocql.ErrNotFound {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to check page existence: %w", err)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue