storage

package
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Dec 22, 2025 License: MIT Imports: 13 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type FileStorage

type FileStorage struct {
	// contains filtered or unexported fields
}

FileStorage implements Storage using JSON files in a directory hierarchy.

Reports are stored in a directory structure like:

{basePath}/history/{project-hash}/{timestamp}_{id-prefix}.json

Where:

  • basePath: Root storage directory (e.g., ~/.cra or ./.cra)
  • project-hash: SHA256 hash of project path (first 16 chars)
  • timestamp: YYYY-MM-DD_HH-MM-SS format
  • id-prefix: First 6 chars of report UUID

This structure provides:

  • Easy manual inspection (human-readable filenames)
  • Project isolation (each project in its own directory)
  • Chronological ordering (timestamp in filename)
  • Uniqueness (UUID prefix prevents collisions)

Example directory structure:

~/.cra/history/
  a1b2c3d4e5f6g7h8/
    2025-12-20_14-30-45_abc123.json
    2025-12-20_15-22-10_def456.json
  9f8e7d6c5b4a3210/
    2025-12-19_10-15-30_ghi789.json

func NewFileStorage

func NewFileStorage(basePath string) (*FileStorage, error)

NewFileStorage creates a new file-based storage backend.

The basePath parameter specifies where reports will be stored. The directory will be created if it doesn't exist. A typical setup uses:

  • ~/.cra for user-level storage
  • ./.cra for project-level storage

Returns an error if the directory cannot be created or accessed.

Example:

storage, err := NewFileStorage(filepath.Join(homeDir, ".cra"))
if err != nil {
    return fmt.Errorf("failed to create storage: %w", err)
}
defer storage.Close()

func (*FileStorage) Close

func (fs *FileStorage) Close() error

Close cleans up resources (no-op for file storage).

func (*FileStorage) Delete

func (fs *FileStorage) Delete(ctx context.Context, id string) error

Delete removes a report by ID.

Searches for and deletes the file containing the report. Returns an error if the report doesn't exist.

func (*FileStorage) GetByID

func (fs *FileStorage) GetByID(ctx context.Context, id string) (*StoredReport, error)

GetByID retrieves a specific report by ID.

Searches all project directories for a report with a matching ID. This is slower than GetLatest as it may need to search multiple directories.

func (*FileStorage) GetLatest

func (fs *FileStorage) GetLatest(ctx context.Context, projectPath string) (*StoredReport, error)

GetLatest retrieves the most recent report for a project.

Reports are sorted by filename (which includes timestamp) to find the latest. Returns nil if no reports exist for the project.

func (*FileStorage) List

func (fs *FileStorage) List(ctx context.Context, projectPath string, opts ListOptions) ([]*ReportMetadata, error)

List returns metadata for reports matching the criteria.

Reports are filtered by project path and ListOptions, then sorted by timestamp (newest first). Only metadata is returned for efficiency.

func (*FileStorage) Save

func (fs *FileStorage) Save(ctx context.Context, report *StoredReport) error

Save stores a report as a JSON file.

The report is written to a file named with the timestamp and ID prefix. If a file with the same name exists, it will be overwritten.

The write is atomic: the file is first written to a temporary location and then renamed to the final path to prevent partial writes.

type ListOptions

type ListOptions struct {
	// Maximum number of results to return (0 = unlimited)
	Limit int

	// Number of results to skip (for pagination)
	Offset int

	// Only include reports after this time (inclusive)
	Since time.Time

	// Only include reports before this time (inclusive)
	Until time.Time
}

ListOptions specifies filtering and pagination for Storage.List().

Use these options to:

  • Limit the number of results (pagination)
  • Skip results (offset-based pagination)
  • Filter by date range (since/until)

Example:

// Get last 10 reports from the past week
opts := ListOptions{
    Limit: 10,
    Since: time.Now().AddDate(0, 0, -7),
}

type ReportMetadata

type ReportMetadata struct {
	// Unique identifier for this report
	ID string `json:"id"`

	// Absolute path to the analyzed project
	ProjectPath string `json:"project_path"`

	// When this analysis was performed
	Timestamp time.Time `json:"timestamp"`

	// Git commit hash at time of analysis (optional)
	GitCommit string `json:"git_commit,omitempty"`

	// Git branch name at time of analysis (optional)
	GitBranch string `json:"git_branch,omitempty"`

	// Summary metrics (optional, for quick display)
	TotalFiles    int     `json:"total_files,omitempty"`
	TotalLines    int     `json:"total_lines,omitempty"`
	AvgComplexity float64 `json:"avg_complexity,omitempty"`
	AvgCoverage   float64 `json:"avg_coverage,omitempty"`
	IssueCount    int     `json:"issue_count,omitempty"`
}

ReportMetadata contains summary information about a stored report.

This type provides lightweight report information for listing operations, without loading the full AnalysisResult. Useful for displaying report history or selecting reports for comparison.

Returned by Storage.List() for efficient browsing of report history.

type SQLiteStorage

type SQLiteStorage struct {
	// contains filtered or unexported fields
}

SQLiteStorage implements Storage using a SQLite database.

Reports are stored in a relational database with the following schema:

  • reports table: Full report data with denormalized metrics
  • Indexes on project_path and timestamp for efficient queries

This backend provides:

  • Efficient querying and filtering
  • Structured storage with integrity constraints
  • Better performance for large numbers of reports
  • ACID guarantees for concurrent access

The database uses WAL (Write-Ahead Logging) mode for better concurrency and prepared statements for performance.

Example usage:

storage, err := NewSQLiteStorage("/path/to/history.db")
if err != nil {
    return err
}
defer storage.Close()

func NewSQLiteStorage

func NewSQLiteStorage(dbPath string) (*SQLiteStorage, error)

NewSQLiteStorage creates a new SQLite-based storage backend.

The dbPath parameter specifies the database file location. The file and any necessary parent directories will be created if they don't exist.

The database is initialized with:

  • Schema creation (reports table and indexes)
  • WAL mode enabled for better concurrency
  • Foreign keys enabled

Returns an error if the database cannot be opened or initialized.

Example:

storage, err := NewSQLiteStorage(filepath.Join(homeDir, ".cra", "history.db"))
if err != nil {
    return fmt.Errorf("failed to create storage: %w", err)
}
defer storage.Close()

func (*SQLiteStorage) Close

func (ss *SQLiteStorage) Close() error

Close closes the database connection.

Should be called when the storage is no longer needed to release database resources.

func (*SQLiteStorage) Delete

func (ss *SQLiteStorage) Delete(ctx context.Context, id string) error

Delete removes a report by ID.

Returns an error if the report doesn't exist.

func (*SQLiteStorage) GetByID

func (ss *SQLiteStorage) GetByID(ctx context.Context, id string) (*StoredReport, error)

GetByID retrieves a specific report by ID.

Uses a primary key lookup for fast retrieval.

func (*SQLiteStorage) GetLatest

func (ss *SQLiteStorage) GetLatest(ctx context.Context, projectPath string) (*StoredReport, error)

GetLatest retrieves the most recent report for a project.

Uses an indexed query on project_path and timestamp for efficiency. Returns nil if no reports exist for the project.

func (*SQLiteStorage) List

func (ss *SQLiteStorage) List(ctx context.Context, projectPath string, opts ListOptions) ([]*ReportMetadata, error)

List returns metadata for reports matching the criteria.

Efficiently queries using denormalized metrics without loading full JSON. Supports filtering by date range and pagination.

func (*SQLiteStorage) Save

func (ss *SQLiteStorage) Save(ctx context.Context, report *StoredReport) error

Save stores a report in the database.

The report is inserted with both the full JSON data and denormalized metrics for efficient querying. If a report with the same ID exists, it will be replaced.

type Storage

type Storage interface {
	// Save stores an analysis report with metadata.
	//
	// The report is assigned a unique ID and stored with the provided metadata
	// (timestamp, Git commit, branch). Returns an error if storage fails.
	//
	// Example:
	//   report := &StoredReport{
	//       ID: "abc-123",
	//       ProjectPath: "/path/to/project",
	//       Timestamp: time.Now(),
	//       GitCommit: "def456",
	//       Result: analysisResult,
	//   }
	//   err := storage.Save(ctx, report)
	Save(ctx context.Context, report *StoredReport) error

	// GetLatest retrieves the most recent report for a project.
	//
	// Returns the latest report based on timestamp, or nil if no reports
	// exist for the project. The projectPath should be an absolute path
	// for consistent matching across runs.
	//
	// Example:
	//   latest, err := storage.GetLatest(ctx, "/path/to/project")
	//   if latest != nil {
	//       // Compare with current analysis
	//   }
	GetLatest(ctx context.Context, projectPath string) (*StoredReport, error)

	// GetByID retrieves a specific report by its unique ID.
	//
	// Returns the report with the given ID, or an error if not found.
	// Useful for retrieving specific historical reports for comparison.
	//
	// Example:
	//   report, err := storage.GetByID(ctx, "abc-123")
	GetByID(ctx context.Context, id string) (*StoredReport, error)

	// List returns reports for a project, optionally filtered and paginated.
	//
	// Returns metadata for matching reports ordered by timestamp (newest first).
	// Use ListOptions to filter by date range and implement pagination.
	//
	// Example:
	//   opts := ListOptions{Limit: 10, Since: oneWeekAgo}
	//   reports, err := storage.List(ctx, "/path/to/project", opts)
	List(ctx context.Context, projectPath string, opts ListOptions) ([]*ReportMetadata, error)

	// Delete removes a report by ID.
	//
	// Returns an error if the report doesn't exist or deletion fails.
	// Use with caution as this operation is irreversible.
	//
	// Example:
	//   err := storage.Delete(ctx, "abc-123")
	Delete(ctx context.Context, id string) error

	// Close cleans up storage resources.
	//
	// Should be called when the storage is no longer needed to release
	// any open connections, file handles, or other resources.
	//
	// Example:
	//   defer storage.Close()
	Close() error
}

Storage defines the interface for persisting and retrieving analysis reports.

Implementations provide different storage backends (file-based, database, etc.) while maintaining a consistent API for saving and loading reports. All operations accept a context for cancellation and timeout support.

The storage layer enables historical tracking and comparison features by persisting analysis results with metadata like timestamps and Git information.

type StoredReport

type StoredReport struct {
	// Unique identifier for this report (UUID)
	ID string `json:"id"`

	// Absolute path to the analyzed project
	ProjectPath string `json:"project_path"`

	// When this analysis was performed
	Timestamp time.Time `json:"timestamp"`

	// Git commit hash at time of analysis (optional)
	GitCommit string `json:"git_commit,omitempty"`

	// Git branch name at time of analysis (optional)
	GitBranch string `json:"git_branch,omitempty"`

	// The complete analysis result
	Result *analyzer.AnalysisResult `json:"result"`
}

StoredReport represents a saved analysis report with metadata.

This type wraps an AnalysisResult with additional metadata needed for historical tracking and comparison:

  • Unique ID for retrieval
  • Project path for grouping reports
  • Timestamp for chronological ordering
  • Git metadata for correlation with code changes

StoredReport is the primary type passed to Storage.Save() and returned from Storage.Get*() methods.

Jump to

Keyboard shortcuts

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