feedstore

package module
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Nov 21, 2025 License: AGPL-3.0 Imports: 14 Imported by: 0

README

Feed Store

Feed Store is a Go library designed to efficiently store and manage feed data (like RSS or Atom) using SQL database backends. It provides a simple interface for adding, retrieving, and querying feed items, supporting SQLite, PostgreSQL, and MySQL.

License

This project is dual-licensed under the following terms:

  • For non-commercial use, you may choose either the GNU Affero General Public License v3.0 (AGPLv3) or a separate commercial license (see below). You can find a copy of the AGPLv3 at: https://www.gnu.org/licenses/agpl-3.0.txt

  • For commercial use, a separate commercial license is required. Commercial licenses are available for various use cases. Please contact me via my contact page to obtain a commercial license.

Description

Feed Store provides a persistent storage solution for feed items parsed from sources like RSS or Atom feeds. It abstracts the underlying database interactions, allowing you to work with feed data through a consistent Go API.

Key Features:

  • SQL Backends: Supports SQLite, PostgreSQL, and MySQL databases.
  • Simple API: Offers straightforward methods for adding, retrieving, and querying feed items.
  • Persistence: Stores feed data durably in your chosen SQL database.

This library focuses solely on the storage aspect. Fetching and parsing feeds should be handled by other libraries (e.g., gofeed).

Installation

go get github.com/dracory/feedstore

Examples

1. Store Initialization:

    // --- Initialize Feed Store ---
    // Provide table names and enable automigration for this example
    store, err := feedstore.NewStore(feedstore.NewStoreOptions{
        DB:                 db,
        FeedTableName:      "feeds", // Choose your feed table name
        LinkTableName:      "links", // Choose your link table name
        AutomigrateEnabled: true,    // Automatically create/update tables
        // DebugEnabled:    true,    // Optional: Enable SQL logging
    })
    if err != nil {
        log.Fatalf("❌ Failed to initialize feed store: %v", err)
    }
    fmt.Println("✅ Feed store initialized (tables migrated if needed).")

2. Feed Operations:

    // --- Create a Feed ---
    feed1 := feedstore.NewFeed().
        SetName("Example Blog Feed").
        SetURL("https://example.com/blog/rss").
        SetStatus(feedstore.FEED_STATUS_ACTIVE).
        SetFetchInterval("3600") // e.g., 1 hour

    err := store.FeedCreate(feed1)
    if err != nil {
        log.Printf("⚠️ Failed to create feed: %v", err)
        return
    }
    fmt.Printf("✅ Feed created successfully: ID=%s, Name=%s\n", feed1.ID(), feed1.Name())

    // --- Find Feed by ID ---
    foundFeed, err := store.FeedFindByID(feed1.ID())
    if err != nil {
        log.Printf("⚠️ Error finding feed %s: %v", feed1.ID(), err)
    } else if foundFeed == nil {
        fmt.Printf("ℹ️ Feed %s not found.\n", feed1.ID())
    } else {
        fmt.Printf("✅ Found feed by ID: %s (Name: %s)\n", foundFeed.ID(), foundFeed.Name())
    }

    // --- List Active Feeds ---
    activeFeeds, err := store.FeedList(feedstore.FeedQuery().
        SetStatus(feedstore.FEED_STATUS_ACTIVE).
        SetLimit(10)) // Limit results
    if err != nil {
        log.Printf("⚠️ Error listing active feeds: %v", err)
    } else {
        fmt.Printf("✅ Found %d active feed(s):\n", len(activeFeeds))
        for _, f := range activeFeeds {
            fmt.Printf("   - ID: %s, Name: %s, Status: %s\n", f.ID(), f.Name(), f.Status())
        }
    }

    // --- Update a Feed ---
    foundFeed.SetMemo("This feed was updated.")
    err = store.FeedUpdate(foundFeed)
    if err != nil {
        log.Printf("⚠️ Error updating feed %s: %v", foundFeed.ID(), err)
    } else {
        fmt.Printf("✅ Feed %s updated successfully.\n", foundFeed.ID())
        // Verify update
        updatedFeed, _ := store.FeedFindByID(foundFeed.ID())
        if updatedFeed != nil {
            fmt.Printf("   Updated Memo: %s\n", updatedFeed.Memo())
        }
    }

    // --- Soft Delete a Feed ---
    // Create another feed to delete
    feedToDelete := feedstore.NewFeed().SetName("Temporary Feed").SetURL("http://temp.com/rss")
    _ = store.FeedCreate(feedToDelete)
    fmt.Printf("   Created temporary feed: %s\n", feedToDelete.ID())

    err = store.FeedSoftDeleteByID(feedToDelete.ID())
    if err != nil {
        log.Printf("⚠️ Error soft deleting feed %s: %v", feedToDelete.ID(), err)
    } else {
        fmt.Printf("✅ Feed %s soft deleted.\n", feedToDelete.ID())
    }

3. Link Operations:


// --- Create Links ---
link1 := feedstore.NewLink().
    SetFeedID(feedID).
    SetTitle("First Blog Post").
    SetURL("https://example.com/blog/post1").
    SetStatus(feedstore.LINK_STATUS_ACTIVE)


err = store.LinkCreate(link1)
if err != nil {
    log.Printf("⚠️ Failed to create link1: %v", err)
} else {
    fmt.Printf("✅ Link created successfully: ID=%s, Title=%s\n", link1.ID(), link1.Title())
}

// --- Find Link by ID ---
foundLink, err := store.LinkFindByID(link1.ID())
if err != nil {
    log.Printf("⚠️ Error finding link %s: %v", link1.ID(), err)
} else if foundLink == nil {
    fmt.Printf("ℹ️ Link %s not found.\n", link1.ID())
} else {
    fmt.Printf("✅ Found link by ID: %s (Title: %s)\n", foundLink.ID(), foundLink.Title())
}

// --- List Links for a Specific Feed ---
feedLinks, err := store.LinkList(feedstore.LinkQuery().
    SetFeedID(feedID). // Filter by the feed's ID
    SetLimit(10))
if err != nil {
    log.Printf("⚠️ Error listing links for feed %s: %v", feedID, err)
} else {
    fmt.Printf("✅ Found %d link(s) for feed %s:\n", len(feedLinks), feedID)
    for _, lnk := range feedLinks {
        fmt.Printf("   - ID: %s, Title: %s, URL: %s\n", lnk.ID(), lnk.Title(), lnk.URL())
    }
}

// --- Update a Link ---
foundLink.SetDescription("Added a description.")
err = store.LinkUpdate(foundLink)
if err != nil {
    log.Printf("⚠️ Error updating link %s: %v", foundLink.ID(), err)
} else {
    fmt.Printf("✅ Link %s updated successfully.\n", foundLink.ID())
    // Verify update
    updatedLink, _ := store.LinkFindByID(foundLink.ID())
    if updatedLink != nil {
        fmt.Printf("   Updated Description: %s\n", updatedLink.Description())
    }
}

// --- Soft Delete a Link ---
err = store.LinkSoftDeleteByID(link2.ID())
if err != nil {
    log.Printf("⚠️ Error soft deleting link %s: %v", link2.ID(), err)
} else {
    fmt.Printf("✅ Link %s soft deleted.\n", link2.ID())
}

Documentation

Index

Constants

View Source
const COLUMN_CHECKED_AT = "checked_at"
View Source
const COLUMN_CREATED_AT = "created_at"
View Source
const COLUMN_DESCRIPTION = "description"
View Source
const COLUMN_FEED_ID = "feed_id"
View Source
const COLUMN_FETCH_INTERVAL = "fetch_interval"
View Source
const COLUMN_ID = "id"
View Source
const COLUMN_LAST_FETCHED_AT = "last_fetched_at"
View Source
const COLUMN_MEMO = "memo"
View Source
const COLUMN_NAME = "name"
View Source
const COLUMN_REPORT = "report"
View Source
const COLUMN_REPORTED_AT = "reported_at"
View Source
const COLUMN_SOFT_DELETED_AT = "soft_deleted_at"
View Source
const COLUMN_STATUS = "status"
View Source
const COLUMN_TIME = "time"
View Source
const COLUMN_TITLE = "title"
View Source
const COLUMN_UPDATED_AT = "updated_at"
View Source
const COLUMN_URL = "url"
View Source
const COLUMN_VIEWS = "views"
View Source
const COLUMN_VOTES_DOWN = "votes_down"
View Source
const COLUMN_VOTES_UP = "votes_up"
View Source
const FEED_STATUS_ACTIVE = "active"
View Source
const FEED_STATUS_INACTIVE = "inactive"
View Source
const LINK_STATUS_ACTIVE = "active"
View Source
const LINK_STATUS_INACTIVE = "inactive"

Variables

This section is empty.

Functions

func NewFeed

func NewFeed() *feedImplementation

func NewFeedFromExistingData

func NewFeedFromExistingData(data map[string]string) *feedImplementation
func NewLink() *linkImplementation

func NewLinkFromExistingData

func NewLinkFromExistingData(data map[string]string) *linkImplementation

Types

type FeedInterface

type FeedInterface interface {
	Data() map[string]string
	DataChanged() map[string]string
	MarkAsNotDirty()

	CreatedAt() string
	CreatedAtCarbon() *carbon.Carbon
	SetCreatedAt(createdAt string) FeedInterface
	Description() string
	SetDescription(description string) FeedInterface
	FetchInterval() string
	SetFetchInterval(fetchInterval string) FeedInterface
	ID() string
	SetID(id string) FeedInterface
	LastFetchedAt() string
	SetLastFetchedAt(lastFetchedAt string) FeedInterface
	Memo() string
	SetMemo(memo string) FeedInterface
	Name() string
	SetName(name string) FeedInterface
	SoftDeletedAt() string
	SoftDeletedAtCarbon() *carbon.Carbon
	SetSoftDeletedAt(softDeletedAt string) FeedInterface
	Status() string
	SetStatus(status string) FeedInterface
	UpdatedAt() string
	UpdatedAtCarbon() *carbon.Carbon
	SetUpdatedAt(updatedAt string) FeedInterface
	URL() string
	SetURL(url string) FeedInterface
}

type FeedQueryInterface

type FeedQueryInterface interface {
	// Validation method
	Validate() error

	// Count related methods
	IsCountOnlySet() bool
	GetCountOnly() bool
	SetCountOnly(countOnly bool) FeedQueryInterface

	// Soft delete related query methods
	IsWithSoftDeletedSet() bool
	GetWithSoftDeleted() bool
	SetWithSoftDeleted(withSoftDeleted bool) FeedQueryInterface

	IsOnlySoftDeletedSet() bool
	GetOnlySoftDeleted() bool
	SetOnlySoftDeleted(onlySoftDeleted bool) FeedQueryInterface

	// Dataset conversion methods
	ToSelectDataset(store StoreInterface) (selectDataset *goqu.SelectDataset, columns []any, err error)

	IsCreatedAtGteSet() bool
	GetCreatedAtGte() string
	SetCreatedAtGte(createdAt string) FeedQueryInterface

	IsCreatedAtLteSet() bool
	GetCreatedAtLte() string
	SetCreatedAtLte(createdAt string) FeedQueryInterface

	IsIDSet() bool
	GetID() string
	SetID(id string) FeedQueryInterface

	IsIDInSet() bool
	GetIDIn() []string
	SetIDIn(ids []string) FeedQueryInterface

	IsLastFetchedAtLteSet() bool
	GetLastFetchedAtLte() string
	SetLastFetchedAtLte(lastFetchedAtLte string) FeedQueryInterface

	IsLastFetchedAtGteSet() bool
	GetLastFetchedAtGte() string
	SetLastFetchedAtGte(lastFetchedAtGte string) FeedQueryInterface

	IsLimitSet() bool
	GetLimit() int
	SetLimit(limit int) FeedQueryInterface

	IsOffsetSet() bool
	GetOffset() int
	SetOffset(offset int) FeedQueryInterface

	IsOrderBySet() bool
	GetOrderBy() string
	SetOrderBy(orderBy string) FeedQueryInterface

	IsOrderDirectionSet() bool
	GetOrderDirection() string
	SetOrderDirection(orderDirection string) FeedQueryInterface

	IsStatusSet() bool
	GetStatus() string
	SetStatus(status string) FeedQueryInterface
	SetStatusIn(statuses []string) FeedQueryInterface

	IsUpdatedAtGteSet() bool
	GetUpdatedAtGte() string
	SetUpdatedAtGte(updatedAt string) FeedQueryInterface

	IsUpdatedAtLteSet() bool
	GetUpdatedAtLte() string
	SetUpdatedAtLte(updatedAt string) FeedQueryInterface
}

FeedQueryInterface defines the interface for querying feeds

func FeedQuery

func FeedQuery() FeedQueryInterface

FeedQuery creates a new feed query

type LinkInterface

type LinkInterface interface {
	Data() map[string]string
	DataChanged() map[string]string
	MarkAsNotDirty()

	CreatedAt() string
	CreatedAtCarbon() *carbon.Carbon
	SetCreatedAt(createdAt string) LinkInterface
	Description() string
	SetDescription(description string) LinkInterface
	FeedID() string
	SetFeedID(feedID string) LinkInterface
	ID() string
	SetID(id string) LinkInterface
	Status() string
	SetStatus(status string) LinkInterface
	Title() string
	SetTitle(title string) LinkInterface
	Time() string
	TimeCarbon() *carbon.Carbon
	SetTime(time string) LinkInterface
	SoftDeletedAt() string
	SoftDeletedAtCarbon() *carbon.Carbon
	SetSoftDeletedAt(softDeletedAt string) LinkInterface
	UpdatedAt() string
	UpdatedAtCarbon() *carbon.Carbon
	SetUpdatedAt(updatedAt string) LinkInterface
	URL() string
	SetURL(url string) LinkInterface
}

type LinkQueryInterface

type LinkQueryInterface interface {
	// Validation method
	Validate() error

	// Count related methods
	IsCountOnlySet() bool
	GetCountOnly() bool
	SetCountOnly(countOnly bool) LinkQueryInterface

	// Soft delete related query methods
	IsWithSoftDeletedSet() bool
	GetWithSoftDeleted() bool
	SetWithSoftDeleted(withSoftDeleted bool) LinkQueryInterface

	IsOnlySoftDeletedSet() bool
	GetOnlySoftDeleted() bool
	SetOnlySoftDeleted(onlySoftDeleted bool) LinkQueryInterface

	// Dataset conversion methods
	ToSelectDataset(store StoreInterface) (selectDataset *goqu.SelectDataset, columns []any, err error)

	IsCreatedAtGteSet() bool
	GetCreatedAtGte() string
	SetCreatedAtGte(createdAt string) LinkQueryInterface

	IsCreatedAtLteSet() bool
	GetCreatedAtLte() string
	SetCreatedAtLte(createdAt string) LinkQueryInterface

	IsFeedIDSet() bool
	GetFeedID() string
	SetFeedID(feedID string) LinkQueryInterface

	IsIDSet() bool
	GetID() string
	SetID(id string) LinkQueryInterface

	IsIDInSet() bool
	GetIDIn() []string
	SetIDIn(ids []string) LinkQueryInterface

	IsLimitSet() bool
	GetLimit() int
	SetLimit(limit int) LinkQueryInterface

	IsOffsetSet() bool
	GetOffset() int
	SetOffset(offset int) LinkQueryInterface

	IsOrderBySet() bool
	GetOrderBy() string
	SetOrderBy(orderBy string) LinkQueryInterface

	IsOrderDirectionSet() bool
	GetOrderDirection() string
	SetOrderDirection(orderDirection string) LinkQueryInterface

	IsStatusSet() bool
	GetStatus() string
	SetStatus(status string) LinkQueryInterface
	SetStatusIn(statuses []string) LinkQueryInterface

	IsURLSet() bool
	GetURL() string
	SetURL(url string) LinkQueryInterface

	IsUpdatedAtGteSet() bool
	GetUpdatedAtGte() string
	SetUpdatedAtGte(updatedAt string) LinkQueryInterface

	IsUpdatedAtLteSet() bool
	GetUpdatedAtLte() string
	SetUpdatedAtLte(updatedAt string) LinkQueryInterface
}

LinkQueryInterface defines the interface for querying links

func LinkQuery

func LinkQuery() LinkQueryInterface

LinkQuery creates a new link query

type NewStoreOptions

type NewStoreOptions struct {
	FeedTableName      string
	LinkTableName      string
	DB                 *sql.DB
	DbDriverName       string
	AutomigrateEnabled bool
	DebugEnabled       bool
}

NewStoreOptions define the options for creating a new block store

type StoreInterface

type StoreInterface interface {
	AutoMigrate() error
	EnableDebug(debug bool)

	GetDriverName() string
	GetFeedTableName() string
	GetLinkTableName() string

	FeedCount(ctx context.Context, query FeedQueryInterface) (int64, error)
	FeedCreate(ctx context.Context, feed FeedInterface) error
	FeedDelete(ctx context.Context, feed FeedInterface) error
	FeedDeleteByID(ctx context.Context, id string) error
	FeedFindByID(ctx context.Context, id string) (FeedInterface, error)
	FeedList(ctx context.Context, query FeedQueryInterface) ([]FeedInterface, error)
	FeedSoftDelete(ctx context.Context, feed FeedInterface) error
	FeedSoftDeleteByID(ctx context.Context, id string) error
	FeedUpdate(ctx context.Context, feed FeedInterface) error

	LinkCount(ctx context.Context, query LinkQueryInterface) (int64, error)
	LinkCreate(ctx context.Context, link LinkInterface) error
	LinkDelete(ctx context.Context, link LinkInterface) error
	LinkDeleteByID(ctx context.Context, id string) error
	LinkFindByID(ctx context.Context, id string) (LinkInterface, error)
	LinkList(ctx context.Context, query LinkQueryInterface) ([]LinkInterface, error)
	LinkSoftDelete(ctx context.Context, link LinkInterface) error
	LinkSoftDeleteByID(ctx context.Context, id string) error
	LinkUpdate(ctx context.Context, link LinkInterface) error
}

func NewStore

func NewStore(opts NewStoreOptions) (StoreInterface, error)

NewStore creates a new block store

Jump to

Keyboard shortcuts

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