blogstore

package module
v1.27.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 21, 2026 License: AGPL-3.0 Imports: 19 Imported by: 0

README

Blog Store

Tests Status Go Report Card PkgGoDev

Stores blog posts to a database table.

Installation

go get -u github.com/dracory/blogstore

Setup

blogStore = blogstore.NewStore(blogstore.NewStoreOptions{
	DB:                 databaseInstance,
	PostTableName:     "blog_post",
	AutomigrateEnabled: true,
	DebugEnabled:       false,
})

Usage

Creating a Post
post := blogstore.NewPost()
post.SetTitle("My First Post").
    SetContent("Post content here...").
    SetStatus(blogstore.STATUS_PUBLISHED)

err := blogStore.PostCreate(ctx, post)
Listing Posts
posts, err := blogStore.PostList(ctx, blogstore.PostQueryOptions{
    Status: blogstore.STATUS_PUBLISHED,
    Limit:  10,
    Offset: 0,
})

MCP (Model Context Protocol)

Blog Store includes an MCP (Model Context Protocol) HTTP handler that allows LLM clients (for example Windsurf) to manage blog posts via JSON-RPC tools.

  • The MCP handler lives in the mcp package
  • It supports MCP JSON-RPC methods (initialize, tools/list, tools/call) and legacy aliases (list_tools, call_tool)
  • It exposes tools such as post_list, post_create, post_get, post_update, and post_delete

See the detailed documentation and examples in: mcp/README.md

Taxonomy System

Blog Store includes a flexible taxonomy system for classifying posts using categories, tags, and custom taxonomies.

Architecture
  • Taxonomy - A classification type (e.g., "category", "tag")
  • Term - An individual item within a taxonomy (e.g., "Technology" category, "go" tag)
  • TermRelation - Links posts to terms with optional ordering
Key Features
  • Hierarchical terms - Terms can have parent/child relationships for nested categories
  • Cached counts - Each term stores a post count to avoid expensive queries
  • Slugs - URL-friendly identifiers with uniqueness per taxonomy
  • Ordered relations - Sequence field for manual term ordering on posts
Usage Examples
// Create a taxonomy
cat := blogstore.NewTaxonomy()
cat.SetName("Categories").SetSlug("category")
store.TaxonomyCreate(ctx, cat)

// Create hierarchical terms
tech := blogstore.NewTerm()
tech.SetTaxonomyID(cat.GetID()).SetName("Technology").SetSlug("technology")
store.TermCreate(ctx, tech)

prog := blogstore.NewTerm()
prog.SetTaxonomyID(cat.GetID()).
    SetParentID(tech.GetID()).
    SetName("Programming").
    SetSlug("programming")
store.TermCreate(ctx, prog)

// Assign terms to a post
store.PostSetTerms(ctx, postID, "category", []string{prog.GetID()})

// Get terms for a post
terms, _ := store.TermListByPostID(ctx, postID, "category")

License

This project is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0). You can find a copy of the license at https://www.gnu.org/licenses/agpl-3.0.en.html

For commercial use, please use my contact page to obtain a commercial license.

Documentation

Index

Constants

View Source
const COLUMN_AUTHOR_ID = "author_id"
View Source
const COLUMN_CANONICAL_URL = "canonical_url"
View Source
const COLUMN_CONTENT = "content"
View Source
const COLUMN_COUNT = "count"
View Source
const COLUMN_CREATED_AT = "created_at"
View Source
const COLUMN_DESCRIPTION = "description"
View Source
const COLUMN_ENTITY_ID = "entity_id"
View Source
const COLUMN_ENTITY_TYPE = "entity_type"
View Source
const COLUMN_FEATURED = "featured"
View Source
const COLUMN_ID = "id"
View Source
const COLUMN_IMAGE_URL = "image_url"
View Source
const COLUMN_MEMO = "memo"
View Source
const COLUMN_METAS = "metas"
View Source
const COLUMN_META_DESCRIPTION = "meta_description"
View Source
const COLUMN_META_KEYWORDS = "meta_keywords"
View Source
const COLUMN_META_ROBOTS = "meta_robots"
View Source
const COLUMN_NAME = "name"
View Source
const COLUMN_PARENT_ID = "parent_id"
View Source
const COLUMN_POST_ID = "post_id"
View Source
const COLUMN_PUBLISHED_AT = "published_at"
View Source
const COLUMN_SEQUENCE = "sequence"
View Source
const COLUMN_SLUG = "slug"
View Source
const COLUMN_SOFT_DELETED_AT = "soft_deleted_at"
View Source
const COLUMN_STATUS = "status"
View Source
const COLUMN_SUMMARY = "summary"
View Source
const COLUMN_TAXONOMY_ID = "taxonomy_id"
View Source
const COLUMN_TERM_ID = "term_id"
View Source
const COLUMN_TITLE = "title"
View Source
const COLUMN_UPDATED_AT = "updated_at"
View Source
const MAX_DATETIME = "9999-12-31 23:59:59"
View Source
const META_KEY_OLD_SLUGS = "_old_slugs"

Meta key names

View Source
const NO = "no"
View Source
const NULL_DATETIME = "0000-00-00 00:00:00"
View Source
const POST_CONTENT_TYPE_BLOCKS = "blocks"
View Source
const POST_CONTENT_TYPE_HTML = "html"
View Source
const POST_CONTENT_TYPE_MARKDOWN = "markdown"
View Source
const POST_CONTENT_TYPE_PLAIN_TEXT = "plain_text"
View Source
const POST_EDITOR_BLOCKAREA = "BlockArea"
View Source
const POST_EDITOR_BLOCKEDITOR = "BlockEditor"
View Source
const POST_EDITOR_HTMLAREA = "HtmlArea"
View Source
const POST_EDITOR_MARKDOWN = "Markdown"
View Source
const POST_EDITOR_TEXTAREA = "TextArea"
View Source
const POST_STATUS_DRAFT = "draft"
View Source
const POST_STATUS_PUBLISHED = "published"
View Source
const POST_STATUS_TRASH = "trash"
View Source
const POST_STATUS_UNPUBLISHED = "unpublished"
View Source
const TAXONOMY_CATEGORY = "category"

Taxonomy types (pre-defined)

View Source
const TAXONOMY_TAG = "tag"
View Source
const VERSIONING_TYPE_POST = "post"
View Source
const YES = "yes"

Variables

This section is empty.

Functions

func BlogNoImageUrl

func BlogNoImageUrl() string

BlogNoImageUrl returns a default image URL when no featured image is set.

func GenerateShortID added in v1.5.0

func GenerateShortID() string

GenerateShortID generates a new 11-character shortened ID using TimestampMicro

func IsShortID added in v1.5.0

func IsShortID(id string) bool

IsShortID checks if an ID appears to be shortened (9-21 chars, alphanumeric)

func NormalizeID added in v1.5.0

func NormalizeID(id string) string

NormalizeID normalizes an ID for lookup (lowercase)

func ShortenID added in v1.5.0

func ShortenID(id string) string

ShortenID shortens any numeric ID string using Crockford Base32

func UnshortenID added in v1.5.0

func UnshortenID(shortID string) (string, error)

UnshortenID attempts to unshorten a Crockford Base32 ID

Types

type NewStoreOptions

type NewStoreOptions struct {
	PostTableName         string
	TaxonomyTableName     string
	TermTableName         string
	TermRelationTableName string
	DB                    *sql.DB
	TimeoutSeconds        int64
	AutomigrateEnabled    bool
	DebugEnabled          bool

	VersioningEnabled   bool
	VersioningTableName string

	TaxonomyEnabled bool
}

NewStoreOptions defines the configuration options for creating a new blog store.

type PostInterface added in v1.8.0

type PostInterface interface {
	// Identity
	// GetID returns the unique identifier of the post.
	GetID() string
	// SetID sets the unique identifier of the post.
	SetID(id string) PostInterface

	// Author
	// GetAuthorID returns the ID of the post author.
	GetAuthorID() string
	// SetAuthorID sets the ID of the post author.
	SetAuthorID(authorID string) PostInterface

	// Content
	// GetTitle returns the post title.
	GetTitle() string
	// SetTitle sets the post title.
	SetTitle(title string) PostInterface
	// GetSlug returns the URL-friendly slug generated from the title.
	GetSlug() string
	// SetSlug sets the URL-friendly slug for this post.
	SetSlug(slug string) PostInterface

	// GetContent returns the main content/body of the post.
	GetContent() string
	// SetContent sets the main content/body of the post.
	SetContent(content string) PostInterface

	// GetSummary returns the post summary/excerpt.
	GetSummary() string
	// SetSummary sets the post summary/excerpt.
	SetSummary(summary string) PostInterface

	// Content Type and Editor
	// GetContentType returns the content type of this post (markdown, html, plain_text, blocks).
	GetContentType() string
	// SetContentType sets the content type of this post.
	SetContentType(contentType string) PostInterface
	// GetEditor returns the editor type for this post.
	GetEditor() string
	// SetEditor sets the editor type for this post.
	SetEditor(editor string) PostInterface

	// IsContentMarkdown returns true if the post content type is markdown.
	IsContentMarkdown() bool
	// IsContentHtml returns true if the post content type is HTML.
	IsContentHtml() bool
	// IsContentPlainText returns true if the post content type is plain text.
	IsContentPlainText() bool
	// IsContentBlocks returns true if the post content type is blocks.
	IsContentBlocks() bool

	// SEO and Meta
	// GetCanonicalURL returns the canonical URL for SEO purposes.
	GetCanonicalURL() string
	// SetCanonicalURL sets the canonical URL for SEO purposes.
	SetCanonicalURL(canonicalURL string) PostInterface

	// GetMetaDescription returns the SEO meta description.
	GetMetaDescription() string
	// SetMetaDescription sets the SEO meta description.
	SetMetaDescription(metaDescription string) PostInterface

	// GetMetaKeywords returns the SEO meta keywords.
	GetMetaKeywords() string
	// SetMetaKeywords sets the SEO meta keywords.
	SetMetaKeywords(metaKeywords string) PostInterface

	// GetMetaRobots returns the SEO robots meta tag value.
	GetMetaRobots() string
	// SetMetaRobots sets the SEO robots meta tag value.
	SetMetaRobots(metaRobots string) PostInterface

	// Featured Image
	// GetImageUrl returns the URL of the post's featured image.
	GetImageUrl() string
	// SetImageUrl sets the URL of the post's featured image.
	SetImageUrl(imageURL string) PostInterface
	// GetImageUrlOrDefault returns the featured image URL, or a default URL if none is set.
	GetImageUrlOrDefault() string

	// Status
	// GetStatus returns the post status (draft, published, trash, etc.).
	GetStatus() string
	// SetStatus sets the post status (draft, published, trash, etc.).
	SetStatus(status string) PostInterface

	// IsDraft returns true if the post status is POST_STATUS_DRAFT.
	IsDraft() bool
	// IsPublished returns true if the post status is POST_STATUS_PUBLISHED.
	IsPublished() bool
	// IsUnpublished returns true if the post status is not published.
	IsUnpublished() bool
	// IsTrashed returns true if the post status is POST_STATUS_TRASH.
	IsTrashed() bool

	// Publishing
	// GetPublishedAt returns the publication timestamp as a string.
	GetPublishedAt() string
	// SetPublishedAt sets the publication timestamp.
	SetPublishedAt(publishedAt string) PostInterface
	// GetPublishedAtCarbon returns the publication timestamp as a carbon.Carbon instance.
	GetPublishedAtCarbon() *carbon.Carbon
	// GetPublishedAtTime returns the publication timestamp as a time.Time instance.
	GetPublishedAtTime() time.Time

	// Timestamps
	// GetCreatedAt returns the creation timestamp as a string.
	GetCreatedAt() string
	// SetCreatedAt sets the creation timestamp.
	SetCreatedAt(createdAt string) PostInterface
	// GetCreatedAtCarbon returns the creation timestamp as a carbon.Carbon instance.
	GetCreatedAtCarbon() *carbon.Carbon
	// GetCreatedAtTime returns the creation timestamp as a time.Time instance.
	GetCreatedAtTime() time.Time

	// GetUpdatedAt returns the last update timestamp as a string.
	GetUpdatedAt() string
	// SetUpdatedAt sets the last update timestamp.
	SetUpdatedAt(updatedAt string) PostInterface
	// GetUpdatedAtCarbon returns the last update timestamp as a carbon.Carbon instance.
	GetUpdatedAtCarbon() *carbon.Carbon

	// GetSoftDeletedAt returns the soft deletion timestamp as a string.
	GetSoftDeletedAt() string
	// SetSoftDeletedAt sets the soft deletion timestamp.
	SetSoftDeletedAt(deletedAt string) PostInterface
	// GetSoftDeletedAtCarbon returns the soft deletion timestamp as a carbon.Carbon instance.
	GetSoftDeletedAtCarbon() *carbon.Carbon

	// Memo
	// GetMemo returns the internal memo/note for the post.
	GetMemo() string
	// SetMemo sets the internal memo/note for the post.
	SetMemo(memo string) PostInterface

	// Featured flag
	// GetFeatured returns the featured status (YES/NO) of the post.
	GetFeatured() string
	// SetFeatured sets the featured status (YES/NO) of the post.
	SetFeatured(featured string) PostInterface

	// Metadata
	// GetMeta retrieves a single metadata value by key.
	GetMeta(key string) string
	// SetMeta sets a single metadata value by key.
	SetMeta(key string, value string) error
	// GetMetas returns all metadata as a map[string]string.
	GetMetas() (map[string]string, error)
	// SetMetas sets all metadata from a map[string]string.
	SetMetas(metas map[string]string) error
	// AddMetas adds multiple metadata key-value pairs to the existing metas.
	AddMetas(metas map[string]string) error

	// Versioning
	// MarshalToVersioning serializes the post data for versioning storage.
	MarshalToVersioning() (string, error)
	// UnmarshalFromVersioning restores post data from a serialized versioning string.
	UnmarshalFromVersioning(content string) error

	// Taxonomy methods
	// TermIDs retrieves the term IDs for a specific taxonomy from the post metadata.
	TermIDs(taxonomySlug string) []string
	// SetTermIDs stores the term IDs for a specific taxonomy in the post metadata.
	SetTermIDs(taxonomySlug string, termIDs []string) PostInterface

	// Convenience helpers
	// CategoryIDs retrieves the category IDs associated with this post.
	CategoryIDs() []string
	// SetCategoryIDs sets the category IDs for this post.
	SetCategoryIDs(ids []string) PostInterface
	// TagIDs retrieves the tag IDs associated with this post.
	TagIDs() []string
	// SetTagIDs sets the tag IDs for this post.
	SetTagIDs(ids []string) PostInterface

	// Old Slug methods (WordPress-style slug history for redirects)
	// GetOldSlugs retrieves the array of historical slugs for redirect purposes.
	GetOldSlugs() []string
	// SetOldSlugs sets the array of historical slugs.
	SetOldSlugs(slugs []string) error
	// AddOldSlug adds a slug to the old slugs history.
	AddOldSlug(slug string) error

	// DataObject methods (from embedded dataobject.DataObject)
	// GetData returns all post data as a map.
	GetData() map[string]string
	// GetDataChanged returns only the fields that have been modified.
	GetDataChanged() map[string]string
	// MarkAsNotDirty clears the dirty state of the post.
	// If no columns specified, marks all fields as not dirty.
	// If columns specified, marks only those columns as not dirty.
	MarkAsNotDirty(columns ...string)
	// MarkAsDirty marks the post as dirty.
	// If no columns specified, marks all fields as dirty.
	// If columns specified, marks only those columns as dirty.
	MarkAsDirty(columns ...string)
	// Get retrieves a value by key from the post data.
	Get(key string) string
	// Set stores a value by key in the post data.
	Set(key string, value string)
	// Hydrate populates the post with data from a map.
	Hydrate(data map[string]string)
	// IsDirty returns true if the post has unsaved changes.
	IsDirty() bool
}

PostInterface defines the interface for blog post operations. Posts represent the main content entity in the blog system with support for multiple content types, versioning, taxonomies, and SEO metadata.

func NewPost

func NewPost() PostInterface

NewPost creates a new Post instance with default values. The post is initialized with a generated ID, draft status, empty content fields, current timestamps, and an empty metadata map.

func NewPostFromExistingData

func NewPostFromExistingData(data map[string]string) PostInterface

NewPostFromExistingData creates a Post instance from existing data. This is useful when hydrating a post from database records.

type PostQueryOptions

type PostQueryOptions struct {
	// ID filters by a single post ID.
	ID string
	// IDIn filters by multiple post IDs.
	IDIn []string
	// Status filters by post status (draft, published, trash, etc.).
	Status string
	// StatusIn filters by multiple post statuses.
	StatusIn []string
	// Slug filters by the post slug.
	Slug string
	// OldSlug filters posts where the old slugs array contains this value.
	OldSlug string
	// Search performs a case-insensitive search on title and content.
	Search string
	// CreatedAtLessThan filters posts created before this timestamp.
	CreatedAtLessThan string
	// CreatedAtGreaterThan filters posts created after this timestamp.
	CreatedAtGreaterThan string
	// Offset is the number of records to skip for pagination.
	Offset int
	// Limit is the maximum number of records to return.
	Limit int
	// SortOrder is the sort direction (asc or desc).
	SortOrder string
	// OrderBy is the field to sort by.
	OrderBy string
	// CountOnly returns only the count, not the actual records.
	CountOnly bool
	// WithDeleted includes soft-deleted posts in the results.
	WithDeleted bool
	// MetaEquals filters posts where the meta JSON column has the specified key-value pair (equality).
	// Example: MetaEquals: map[string]string{"content_type": "plain_text"}
	MetaEquals map[string]string
	// MetaArrayContains filters posts where the meta JSON column's array field contains the specified value.
	// Example: MetaArrayContains: map[string]string{"_old_slugs": "11"}
	MetaArrayContains map[string]string
}

PostQueryOptions defines the query parameters for retrieving posts. These options allow filtering, sorting, and pagination of post results.

type StoreInterface

type StoreInterface interface {
	// GetPostTableName returns the post table name
	GetPostTableName() string
	// SetPostTableName sets the post table name
	SetPostTableName(tableName string)

	// GetTaxonomyTableName returns the taxonomy table name
	GetTaxonomyTableName() string
	// SetTaxonomyTableName sets the taxonomy table name
	SetTaxonomyTableName(tableName string)

	// GetTermTableName returns the term table name
	GetTermTableName() string
	// SetTermTableName sets the term table name
	SetTermTableName(tableName string)

	// GetTermRelationTableName returns the term relation table name
	GetTermRelationTableName() string
	// SetTermRelationTableName sets the term relation table name
	SetTermRelationTableName(tableName string)

	// MigrateDown drops the blog store tables
	MigrateDown(ctx context.Context, tx ...*sql.Tx) error
	// MigrateUp creates the blog store tables
	MigrateUp(ctx context.Context, tx ...*sql.Tx) error

	// EnableDebug toggles debug mode logging for database operations.
	// Returns the StoreInterface to allow method chaining.
	EnableDebug(debug bool) StoreInterface

	// VersioningEnabled returns true if versioning support is enabled for this store.
	VersioningEnabled() bool

	// TaxonomyEnabled returns true if taxonomy support is enabled for this store.
	TaxonomyEnabled() bool

	// PostCount returns the total number of posts matching the provided query options.
	// Uses PostQueryOptions to filter by status, type, or other criteria.
	PostCount(ctx context.Context, options PostQueryOptions) (int64, error)

	// PostCreate inserts a new post into the store.
	// Returns an error if the post cannot be created (e.g., duplicate ID or validation failure).
	PostCreate(ctx context.Context, post PostInterface) error

	// PostDelete permanently removes a post from the store.
	// This is a hard delete that cannot be undone.
	PostDelete(ctx context.Context, post PostInterface) error

	// PostDeleteByID permanently removes a post by its ID.
	// Returns an error if the post does not exist.
	PostDeleteByID(ctx context.Context, postID string) error

	// PostFindByID retrieves a post by its unique identifier.
	// Returns the post and nil error on success, or nil and an error if not found.
	PostFindByID(ctx context.Context, id string) (PostInterface, error)

	// PostFindBySlug retrieves a post by its slug.
	// Returns the post and nil error on success, or nil and an error if not found.
	PostFindBySlug(ctx context.Context, slug string) (PostInterface, error)

	// PostFindByOldSlug retrieves a post by its old slug (for redirect handling).
	// Returns the post and nil error on success, or nil and an error if not found.
	PostFindByOldSlug(ctx context.Context, oldSlug string) (PostInterface, error)

	// PostList retrieves a list of posts matching the provided query options.
	// Supports pagination, sorting, and filtering through PostQueryOptions.
	PostList(ctx context.Context, options PostQueryOptions) ([]PostInterface, error)

	// PostSoftDelete marks a post as deleted without removing it from the database.
	// The post can be restored later. Requires versioning to be enabled.
	PostSoftDelete(ctx context.Context, post PostInterface) error

	// PostSoftDeleteByID marks a post as deleted by ID without removing it from the database.
	// Returns an error if the post does not exist.
	PostSoftDeleteByID(ctx context.Context, postID string) error

	// PostTrash moves a post to the trash status.
	// Trashed posts are not visible in normal queries but can be restored.
	PostTrash(ctx context.Context, post PostInterface) error

	// PostUpdate modifies an existing post in the store.
	// Returns an error if the post does not exist or validation fails.
	PostUpdate(ctx context.Context, post PostInterface) error

	// VersioningCreate saves a new version record for a post.
	VersioningCreate(ctx context.Context, versioning VersioningInterface) error

	// VersioningDelete permanently removes a versioning record.
	VersioningDelete(ctx context.Context, versioning VersioningInterface) error

	// VersioningDeleteByID permanently removes a versioning record by ID.
	VersioningDeleteByID(ctx context.Context, id string) error

	// VersioningFindByID retrieves a specific version record by ID.
	VersioningFindByID(ctx context.Context, versioningID string) (VersioningInterface, error)

	// VersioningList retrieves version records matching the provided query.
	VersioningList(ctx context.Context, query VersioningQueryInterface) ([]VersioningInterface, error)

	// VersioningSoftDelete marks a version record as deleted without permanent removal.
	VersioningSoftDelete(ctx context.Context, versioning VersioningInterface) error

	// VersioningSoftDeleteByID marks a version record as deleted by ID.
	VersioningSoftDeleteByID(ctx context.Context, id string) error

	// VersioningUpdate modifies an existing version record.
	VersioningUpdate(ctx context.Context, versioning VersioningInterface) error

	// TaxonomyCount returns the number of taxonomies matching the query options.
	TaxonomyCount(ctx context.Context, options TaxonomyQueryOptions) (int64, error)

	// TaxonomyCreate inserts a new taxonomy into the store.
	TaxonomyCreate(ctx context.Context, taxonomy TaxonomyInterface) error

	// TaxonomyDelete permanently removes a taxonomy from the store.
	TaxonomyDelete(ctx context.Context, taxonomy TaxonomyInterface) error

	// TaxonomyFindByID retrieves a taxonomy by its unique identifier.
	TaxonomyFindByID(ctx context.Context, id string) (TaxonomyInterface, error)

	// TaxonomyFindBySlug retrieves a taxonomy by its URL-friendly slug.
	TaxonomyFindBySlug(ctx context.Context, slug string) (TaxonomyInterface, error)

	// TaxonomyList retrieves taxonomies matching the provided query options.
	TaxonomyList(ctx context.Context, options TaxonomyQueryOptions) ([]TaxonomyInterface, error)

	// TaxonomyUpdate modifies an existing taxonomy.
	TaxonomyUpdate(ctx context.Context, taxonomy TaxonomyInterface) error

	// TermCount returns the number of terms matching the query options.
	TermCount(ctx context.Context, options TermQueryOptions) (int64, error)

	// TermCreate inserts a new term into the store.
	TermCreate(ctx context.Context, term TermInterface) error

	// TermDelete permanently removes a term from the store.
	TermDelete(ctx context.Context, term TermInterface) error

	// TermFindByID retrieves a term by its unique identifier.
	TermFindByID(ctx context.Context, id string) (TermInterface, error)

	// TermFindBySlug retrieves a term by its taxonomy slug and term slug.
	TermFindBySlug(ctx context.Context, taxonomySlug, termSlug string) (TermInterface, error)

	// TermList retrieves terms matching the provided query options.
	TermList(ctx context.Context, options TermQueryOptions) ([]TermInterface, error)

	// TermUpdate modifies an existing term.
	TermUpdate(ctx context.Context, term TermInterface) error

	// PostAddTerm appends a term to a post (adds at the end of the sequence).
	// Automatically calculates the next available sequence number.
	// Returns an error if taxonomy features are not enabled.
	PostAddTerm(ctx context.Context, postID string, termID string) error

	// PostInsertTermAt associates a term with a post at the specified sequence/order.
	PostInsertTermAt(ctx context.Context, postID string, termID string, sequence int) error

	// PostMoveTermTo moves a term to a specific sequence position on a post.
	// Reorders existing terms by pushing subsequent terms down (incrementing their sequence).
	// Returns an error if the term is not associated with the post.
	PostMoveTermTo(ctx context.Context, postID string, termID string, sequence int) error

	// PostRemoveTerm dissociates a term from a post.
	PostRemoveTerm(ctx context.Context, postID string, termID string) error

	// TermListByPostID retrieves all terms associated with a post for a specific taxonomy.
	TermListByPostID(ctx context.Context, postID string, taxonomySlug string) ([]TermInterface, error)

	// PostSetTerms replaces all terms for a post within a taxonomy with the provided term IDs.
	PostSetTerms(ctx context.Context, postID string, taxonomySlug string, termIDs []string) error

	// PostListByTermID retrieves all posts associated with a specific term ID.
	PostListByTermID(ctx context.Context, termID string, options PostQueryOptions) ([]PostInterface, error)

	// TermIncrementCount increases the usage count for a term.
	TermIncrementCount(ctx context.Context, termID string) error

	// TermDecrementCount decreases the usage count for a term.
	TermDecrementCount(ctx context.Context, termID string) error
}

StoreInterface defines the complete interface for blog post storage operations, including post management, taxonomy/term handling, and optional versioning support.

func NewStore

func NewStore(opts NewStoreOptions) (StoreInterface, error)

NewStore creates a new blog store with the provided options. It validates required fields, sets defaults for optional fields, and optionally runs AutoMigrate. Returns a StoreInterface for interacting with posts, taxonomies, and terms.

type TaxonomyInterface added in v1.9.0

type TaxonomyInterface interface {
	// Identity
	// GetID returns the unique identifier of the taxonomy.
	GetID() string
	// SetID sets the unique identifier of the taxonomy.
	SetID(id string) TaxonomyInterface

	// Display
	// GetName returns the display name of the taxonomy.
	GetName() string
	// SetName sets the display name of the taxonomy.
	SetName(name string) TaxonomyInterface

	// URL slug (e.g., "category", "tag")
	// GetSlug returns the URL-friendly slug of the taxonomy.
	GetSlug() string
	// SetSlug sets the URL-friendly slug of the taxonomy.
	SetSlug(slug string) TaxonomyInterface

	// Description
	// GetDescription returns the description of the taxonomy.
	GetDescription() string
	// SetDescription sets the description of the taxonomy.
	SetDescription(description string) TaxonomyInterface

	// Timestamps
	// GetCreatedAt returns the creation timestamp as a string.
	GetCreatedAt() string
	// SetCreatedAt sets the creation timestamp.
	SetCreatedAt(createdAt string) TaxonomyInterface
	// GetCreatedAtCarbon returns the creation timestamp as a carbon.Carbon instance.
	GetCreatedAtCarbon() *carbon.Carbon
	// GetCreatedAtTime returns the creation timestamp as a time.Time instance.
	GetCreatedAtTime() time.Time

	// GetUpdatedAt returns the last update timestamp as a string.
	GetUpdatedAt() string
	// SetUpdatedAt sets the last update timestamp.
	SetUpdatedAt(updatedAt string) TaxonomyInterface
	// GetUpdatedAtCarbon returns the last update timestamp as a carbon.Carbon instance.
	GetUpdatedAtCarbon() *carbon.Carbon
	// GetUpdatedAtTime returns the last update timestamp as a time.Time instance.
	GetUpdatedAtTime() time.Time

	// DataObject methods (from embedded dataobject.DataObject)
	GetData() map[string]string
	GetDataChanged() map[string]string
	// MarkAsNotDirty clears the dirty state of the taxonomy.
	// If no columns specified, marks all fields as not dirty.
	// If columns specified, marks only those columns as not dirty.
	MarkAsNotDirty(columns ...string)
	// MarkAsDirty marks the taxonomy as dirty.
	// If no columns specified, marks all fields as dirty.
	// If columns specified, marks only those columns as dirty.
	MarkAsDirty(columns ...string)
	Get(key string) string
	Set(key string, value string)
	Hydrate(data map[string]string)
	IsDirty() bool
}

TaxonomyInterface defines the interface for taxonomy types (category, tag, etc.). Taxonomies are used to group and classify content within the blog system.

func NewTaxonomy added in v1.9.0

func NewTaxonomy() TaxonomyInterface

NewTaxonomy creates a new Taxonomy instance with default values. The taxonomy is initialized with a generated ID, empty name/slug/description, and current timestamps for created_at and updated_at.

func NewTaxonomyFromExistingData added in v1.9.0

func NewTaxonomyFromExistingData(data map[string]string) TaxonomyInterface

NewTaxonomyFromExistingData creates a Taxonomy instance from existing data. This is useful when hydrating a taxonomy from database records.

type TaxonomyQueryOptions added in v1.9.0

type TaxonomyQueryOptions struct {
	ID        string
	Slug      string
	Search    string
	Limit     int
	Offset    int
	OrderBy   string
	SortOrder string
	CountOnly bool
}

TaxonomyQueryOptions defines query options for listing taxonomies

type TermInterface added in v1.9.0

type TermInterface interface {
	// Identity
	// GetID returns the unique identifier of the term.
	GetID() string
	// SetID sets the unique identifier of the term.
	SetID(id string) TermInterface

	// Relationships
	// GetTaxonomyID returns the ID of the taxonomy this term belongs to.
	GetTaxonomyID() string
	// SetTaxonomyID sets the ID of the taxonomy this term belongs to.
	SetTaxonomyID(taxonomyID string) TermInterface

	// For hierarchy (empty if root)
	// GetParentID returns the ID of the parent term (for hierarchical terms).
	GetParentID() string
	// SetParentID sets the ID of the parent term (for hierarchical terms).
	SetParentID(parentID string) TermInterface

	// For ordering subcategories within parent (0 = default)
	// GetSequence returns the display sequence/order of the term.
	GetSequence() int
	// SetSequence sets the display sequence/order of the term.
	SetSequence(sequence int) TermInterface

	// Display
	// GetName returns the display name of the term.
	GetName() string
	// SetName sets the display name of the term.
	SetName(name string) TermInterface

	// URL slug
	// GetSlug returns the URL-friendly slug of the term.
	GetSlug() string
	// SetSlug sets the URL-friendly slug of the term.
	SetSlug(slug string) TermInterface

	// Description
	// GetDescription returns the description of the term.
	GetDescription() string
	// SetDescription sets the description of the term.
	SetDescription(description string) TermInterface

	// Cached post count
	// GetCount returns the number of posts associated with this term.
	GetCount() int
	// SetCount sets the number of posts associated with this term.
	SetCount(count int) TermInterface

	// Timestamps
	// GetCreatedAt returns the creation timestamp as a string.
	GetCreatedAt() string
	// SetCreatedAt sets the creation timestamp.
	SetCreatedAt(createdAt string) TermInterface
	// GetCreatedAtCarbon returns the creation timestamp as a carbon.Carbon instance.
	GetCreatedAtCarbon() *carbon.Carbon
	// GetCreatedAtTime returns the creation timestamp as a time.Time instance.
	GetCreatedAtTime() time.Time

	// GetUpdatedAt returns the last update timestamp as a string.
	GetUpdatedAt() string
	// SetUpdatedAt sets the last update timestamp.
	SetUpdatedAt(updatedAt string) TermInterface
	// GetUpdatedAtCarbon returns the last update timestamp as a carbon.Carbon instance.
	GetUpdatedAtCarbon() *carbon.Carbon
	// GetUpdatedAtTime returns the last update timestamp as a time.Time instance.
	GetUpdatedAtTime() time.Time

	// DataObject methods (from embedded dataobject.DataObject)
	// GetData returns all term data as a map.
	GetData() map[string]string
	// GetDataChanged returns only the fields that have been modified.
	GetDataChanged() map[string]string
	// MarkAsNotDirty clears the dirty state of the term.
	// If no columns specified, marks all fields as not dirty.
	// If columns specified, marks only those columns as not dirty.
	MarkAsNotDirty(columns ...string)
	// MarkAsDirty marks the term as dirty.
	// If no columns specified, marks all fields as dirty.
	// If columns specified, marks only those columns as dirty.
	MarkAsDirty(columns ...string)
	// Get retrieves a value by key from the term data.
	Get(key string) string
	// Set stores a value by key in the term data.
	Set(key string, value string)
	// Hydrate populates the term with data from a map.
	Hydrate(data map[string]string)
	// IsDirty returns true if the term has unsaved changes.
	IsDirty() bool
}

TermInterface defines the interface for terms within taxonomies. Terms are individual items within a taxonomy (e.g., "Technology" within "Categories").

func NewTerm added in v1.9.0

func NewTerm() TermInterface

NewTerm creates a new Term instance with default values. The term is initialized with a generated ID, empty taxonomy/parent IDs, zero sequence, empty name/slug/description, zero count, and current timestamps.

func NewTermFromExistingData added in v1.9.0

func NewTermFromExistingData(data map[string]string) TermInterface

NewTermFromExistingData creates a Term instance from existing data. This is useful when hydrating a term from database records.

type TermQueryOptions added in v1.9.0

type TermQueryOptions struct {
	ID           string
	IDIn         []string
	TaxonomyID   string
	TaxonomySlug string
	ParentID     string
	Slug         string
	Search       string
	Limit        int
	Offset       int
	OrderBy      string
	SortOrder    string
	CountOnly    bool
}

TermQueryOptions defines query options for listing terms

type TermRelationInterface added in v1.9.0

type TermRelationInterface interface {
	// Identity
	// GetID returns the unique identifier of the term relation.
	GetID() string
	// SetID sets the unique identifier of the term relation.
	SetID(id string) TermRelationInterface

	// Relationships
	// GetPostID returns the ID of the post in this relation.
	GetPostID() string
	// SetPostID sets the ID of the post in this relation.
	SetPostID(postID string) TermRelationInterface

	// GetTermID returns the ID of the term in this relation.
	GetTermID() string
	// SetTermID sets the ID of the term in this relation.
	SetTermID(termID string) TermRelationInterface

	// For manual ordering (0 = default)
	// GetSequence returns the display sequence/order of the relation.
	GetSequence() int
	// SetSequence sets the display sequence/order of the relation.
	SetSequence(sequence int) TermRelationInterface

	// Timestamps
	// GetCreatedAt returns the creation timestamp as a string.
	GetCreatedAt() string
	// SetCreatedAt sets the creation timestamp.
	SetCreatedAt(createdAt string) TermRelationInterface
	// GetCreatedAtCarbon returns the creation timestamp as a carbon.Carbon instance.
	GetCreatedAtCarbon() *carbon.Carbon
	// GetCreatedAtTime returns the creation timestamp as a time.Time instance.
	GetCreatedAtTime() time.Time

	// GetUpdatedAt returns the last update timestamp as a string.
	GetUpdatedAt() string
	// SetUpdatedAt sets the last update timestamp.
	SetUpdatedAt(updatedAt string) TermRelationInterface
	// GetUpdatedAtCarbon returns the last update timestamp as a carbon.Carbon instance.
	GetUpdatedAtCarbon() *carbon.Carbon
	// GetUpdatedAtTime returns the last update timestamp as a time.Time instance.
	GetUpdatedAtTime() time.Time

	// DataObject methods (from embedded dataobject.DataObject)
	// GetData returns all term relation data as a map.
	GetData() map[string]string
	// GetDataChanged returns only the fields that have been modified.
	GetDataChanged() map[string]string
	// MarkAsNotDirty clears the dirty state of the term relation.
	// If no columns specified, marks all fields as not dirty.
	// If columns specified, marks only those columns as not dirty.
	MarkAsNotDirty(columns ...string)
	// MarkAsDirty marks the term relation as dirty.
	// If no columns specified, marks all fields as dirty.
	// If columns specified, marks only those columns as dirty.
	MarkAsDirty(columns ...string)
	// Get retrieves a value by key from the term relation data.
	Get(key string) string
	// Set stores a value by key in the term relation data.
	Set(key string, value string)
	// Hydrate populates the term relation with data from a map.
	Hydrate(data map[string]string)
	// IsDirty returns true if the term relation has unsaved changes.
	IsDirty() bool
}

TermRelationInterface defines the interface for post-term relationships. Term relations link posts to taxonomy terms.

func NewTermRelation added in v1.9.0

func NewTermRelation() TermRelationInterface

NewTermRelation creates a new TermRelation instance with default values. The relation is initialized with a generated ID, empty post/term IDs, zero sequence, and current timestamps.

func NewTermRelationFromExistingData added in v1.9.0

func NewTermRelationFromExistingData(data map[string]string) TermRelationInterface

NewTermRelationFromExistingData creates a TermRelation instance from existing data. This is useful when hydrating a term relation from database records.

type TermRelationQueryOptions added in v1.9.0

type TermRelationQueryOptions struct {
	PostID       string
	TermID       string
	TaxonomyID   string
	TaxonomySlug string
}

TermRelationQueryOptions defines query options for listing term relations

type VersioningInterface added in v1.4.0

type VersioningInterface interface {
	IsSoftDeleted() bool

	ID() string
	SetID(id string) VersioningInterface

	EntityType() string
	SetEntityType(entityType string) VersioningInterface

	EntityID() string
	SetEntityID(entityID string) VersioningInterface

	Content() string
	SetContent(content string) VersioningInterface

	GetCreatedAt() string
	GetCreatedAtCarbon() *carbon.Carbon
	SetCreatedAt(createdAt string) VersioningInterface

	GetSoftDeletedAt() string
	GetSoftDeletedAtCarbon() *carbon.Carbon
	SetSoftDeletedAt(softDeletedAt string) VersioningInterface
}

VersioningInterface represents a version entry for tracking entity changes over time.

func NewVersioning added in v1.4.0

func NewVersioning() VersioningInterface

NewVersioning creates a new VersioningInterface instance. This is used to create a new version entry for tracking entity changes.

func NewVersioningFromExistingData added in v1.25.0

func NewVersioningFromExistingData(data map[string]string) VersioningInterface

NewVersioningFromExistingData creates a versioning from existing data.

type VersioningQueryInterface added in v1.4.0

type VersioningQueryInterface interface {
	Validate() error

	Columns() []string
	SetColumns(columns []string) VersioningQueryInterface

	HasCountOnly() bool
	IsCountOnly() bool
	SetCountOnly(countOnly bool) VersioningQueryInterface

	HasID() bool
	ID() string
	SetID(id string) VersioningQueryInterface

	HasEntityID() bool
	EntityID() string
	SetEntityID(entityID string) VersioningQueryInterface

	HasEntityType() bool
	EntityType() string
	SetEntityType(entityType string) VersioningQueryInterface

	HasOffset() bool
	Offset() int64
	SetOffset(offset int64) VersioningQueryInterface

	HasLimit() bool
	Limit() int
	SetLimit(limit int) VersioningQueryInterface

	HasSortOrder() bool
	SortOrder() string
	SetSortOrder(sortOrder string) VersioningQueryInterface

	HasOrderBy() bool
	OrderBy() string
	SetOrderBy(orderBy string) VersioningQueryInterface

	HasSoftDeletedIncluded() bool
	SoftDeletedIncluded() bool
	SetSoftDeletedIncluded(includeSoftDeleted bool) VersioningQueryInterface
}

VersioningQueryInterface provides query options for retrieving version entries.

func NewVersioningQuery added in v1.4.0

func NewVersioningQuery() VersioningQueryInterface

NewVersioningQuery creates a new VersioningQueryInterface instance. This is used to query version entries with filtering and sorting options.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL