sqlfilestore

package module
v1.6.0 Latest Latest
Warning

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

Go to latest
Published: Jun 20, 2026 License: GPL-3.0 Imports: 12 Imported by: 1

README

SQL File Store

tests Go Report Card PkgGoDev

SQL File Store persists a hierarchical file-system-like structure in a relational database. It handles record creation, querying, soft deletion, and path recalculation for nested directories and files, while keeping a root directory available out of the box.

Features

  • Automatic schema creation (automigration) with a configurable table name.
  • Strongly typed Record helper with builders for files and directories.
  • CRUD helpers: create, update, hard delete, soft delete, and list with filtering options.
  • Recursive path recalculation to keep child paths in sync with renamed parents.
  • Works with standard database/sql connections and supports multiple SQL drivers through query builders.

Installation

go get github.com/dracory/sqlfilestore

Quick Start

package main

import (
    "database/sql"

    "github.com/dracory/sqlfilestore"
    _ "modernc.org/sqlite" // driver
)

func main() {
    db, err := sql.Open("sqlite", ":memory:?parseTime=true")
    if err != nil {
        panic(err)
    }

    store, err := sqlfilestore.NewStore(sqlfilestore.NewStoreOptions{
        DB:                 db,
        TableName:          "file_records",
        AutomigrateEnabled: true,
    })
    if err != nil {
        panic(err)
    }

    file := sqlfilestore.NewFile().
        SetParentID(sqlfilestore.ROOT_ID).
        SetName("example.txt").
        SetPath("/example.txt").
        SetExtension("txt").
        SetContents("Hello, world!")

    if err := store.RecordCreate(file); err != nil {
        panic(err)
    }
}

The example mirrors the test setup used for the in-memory SQLite driver.

Working with Records

All records share a common Record model. File and directory helpers pre-configure type-specific fields:

  • NewDirectory() sets type to directory, zeroes size, and clears file-only fields.
  • NewFile() sets type to file and leaves contents configurable.
  • NewRecord() creates a bare record with generated ID and timestamps.

Each record exposes setters/getters for metadata including name, path, parent ID, file size, extension, and timestamps.

Creating Directories
dir := sqlfilestore.NewDirectory().
    SetParentID(sqlfilestore.ROOT_ID).
    SetName("docs").
    SetPath("/docs")

if err := store.RecordCreate(dir); err != nil {
    // handle error
}
Updating Paths

Rename operations require updating the stored path. Use RecordRecalculatePath to refresh a record and its descendants after changing the name.

dir.SetName("manuals")
if err := store.RecordUpdate(dir); err == nil {
    _ = store.RecordRecalculatePath(dir, nil)
}

Querying Data

RecordQueryOptions lets you filter by ID, parent, type, path, timestamps, and sorting options.

records, err := store.RecordList(sqlfilestore.RecordQueryOptions{
    ParentID: sqlfilestore.ROOT_ID,
    Type:     sqlfilestore.TYPE_FILE,
    OrderBy:  "created_at",
    SortOrder: "asc",
})

Use RecordFindByID and RecordFindByPath for single-record lookups.

Soft Deletes vs. Hard Deletes

  • RecordSoftDeleteByID keeps the record while setting deleted_at for reversible removals.
  • RecordDeleteByID permanently removes a record, ensuring directories are empty beforehand.

Soft-deleted records are excluded by default; enable WithSoftDeleted in query options to include them.

Debugging

Enable SQL logging with store.EnableDebug(true) to print generated statements before execution.

Running Tests

The repository includes comprehensive tests that demonstrate typical interactions with the store.

go test ./...

License

GPL-3.0. See LICENSE.

Documentation

Index

Constants

View Source
const (
	COLUMN_ID              = "id"
	COLUMN_PARENT_ID       = "parent_id"
	COLUMN_NAME            = "name"
	COLUMN_PATH            = "path"
	COLUMN_TYPE            = "type"
	COLUMN_SIZE            = "size"
	COLUMN_EXTENSION       = "extension"
	COLUMN_CONTENTS        = "contents"
	COLUMN_CREATED_AT      = "created_at"
	COLUMN_UPDATED_AT      = "updated_at"
	COLUMN_SOFT_DELETED_AT = "soft_deleted_at"
)

Database column names used in the file records table.

View Source
const MAX_DATETIME = "9999-12-31 23:59:59"

MAX_DATETIME is a far-future datetime used as the default soft-delete sentinel.

View Source
const PATH_SEPARATOR = "/"

PATH_SEPARATOR is the path delimiter used throughout the file store.

View Source
const ROOT_ID = "0"

ROOT_ID is the ID of the root directory record.

View Source
const ROOT_PATH = PATH_SEPARATOR

ROOT_PATH is the path of the root directory.

View Source
const TYPE_DIRECTORY = "directory"

TYPE_DIRECTORY is the record type value for directories.

View Source
const TYPE_FILE = "file"

TYPE_FILE is the record type value for files.

Variables

This section is empty.

Functions

This section is empty.

Types

type NewStoreOptions

type NewStoreOptions struct {
	TableName          string
	DB                 *sql.DB
	AutomigrateEnabled bool
	DebugEnabled       bool
}

NewStoreOptions defines the configuration options for creating a new Store.

type Record

type Record struct {
	orm.ShortID

	ParentIDField  string `db:"parent_id"`
	NameField      string `db:"name"`
	PathField      string `db:"path"`
	TypeField      string `db:"type"`
	SizeField      string `db:"size"`
	ExtensionField string `db:"extension"`
	ContentsField  string `db:"contents"`

	CreatedAtField orm.CreatedAt
	UpdatedAtField orm.UpdatedAt
	soft_delete.SoftDeletesMaxDate
}

Record represents a file or directory entry in the hierarchical file store.

func NewDirectory

func NewDirectory() *Record

NewDirectory creates a new Record preconfigured as a directory.

func NewFile

func NewFile() *Record

NewFile creates a new Record preconfigured as a file.

func NewRecord

func NewRecord() *Record

NewRecord creates a new Record with default values.

func NewRecordFromExistingData

func NewRecordFromExistingData(data map[string]string) *Record

NewRecordFromExistingData creates a Record from a map of existing data.

func (*Record) Contents

func (o *Record) Contents() string

Contents returns the contents of the record.

func (*Record) CreatedAt

func (o *Record) CreatedAt() string

CreatedAt returns the created at time of the record.

func (*Record) DeletedAt

func (o *Record) DeletedAt() string

DeletedAt returns the soft deleted at time of the record.

func (*Record) Extension

func (o *Record) Extension() string

Extension returns the extension of the record.

func (*Record) GetCreatedAtCarbon added in v1.5.0

func (o *Record) GetCreatedAtCarbon() *carbon.Carbon

GetCreatedAtCarbon returns the created at time as a carbon object.

func (*Record) GetDeletedAtCarbon added in v1.5.0

func (o *Record) GetDeletedAtCarbon() *carbon.Carbon

GetDeletedAtCarbon returns the soft deleted at time as a carbon object.

func (*Record) GetUpdatedAtCarbon added in v1.5.0

func (o *Record) GetUpdatedAtCarbon() *carbon.Carbon

GetUpdatedAtCarbon returns the updated at time as a carbon object.

func (*Record) ID

func (o *Record) ID() string

ID returns the id of the record.

func (*Record) IsDirectory

func (o *Record) IsDirectory() bool

IsDirectory returns true if this record represents a directory.

func (*Record) IsFile

func (o *Record) IsFile() bool

IsFile returns true if this record represents a file.

func (*Record) IsSoftDeleted added in v1.5.0

func (o *Record) IsSoftDeleted() bool

IsSoftDeleted returns true if the record is soft deleted.

func (*Record) Name

func (o *Record) Name() string

Name returns the name of the record.

func (*Record) ParentID

func (o *Record) ParentID() string

ParentID returns the parent id of the record.

func (*Record) Path

func (o *Record) Path() string

Path returns the path of the record.

func (*Record) SetContents

func (o *Record) SetContents(fileContents string) *Record

SetContents sets the contents of the record.

func (*Record) SetCreatedAt

func (o *Record) SetCreatedAt(createdAt string) *Record

SetCreatedAt sets the created at time of the record.

func (*Record) SetDeletedAt

func (o *Record) SetDeletedAt(deletedAt string) *Record

SetDeletedAt sets the soft deleted at time of the record.

func (*Record) SetExtension

func (o *Record) SetExtension(extension string) *Record

SetExtension sets the extension of the record.

func (*Record) SetID

func (o *Record) SetID(id string) *Record

SetID sets the id of the record.

func (*Record) SetName

func (o *Record) SetName(name string) *Record

SetName sets the name of the record.

func (*Record) SetParentID

func (o *Record) SetParentID(parentID string) *Record

SetParentID sets the parent id of the record.

func (*Record) SetPath

func (o *Record) SetPath(filePath string) *Record

SetPath sets the file path. As all paths must start with "/" adds a "/" if not present. Any trailing spaces is also trimmed

func (*Record) SetSize

func (o *Record) SetSize(fileSize string) *Record

SetSize sets the size of the record.

func (*Record) SetType

func (o *Record) SetType(fileType string) *Record

SetType sets the type of the record.

func (*Record) SetUpdatedAt

func (o *Record) SetUpdatedAt(updatedAt string) *Record

SetUpdatedAt sets the updated at time of the record.

func (*Record) Size

func (o *Record) Size() string

Size returns the size of the record.

func (*Record) Type

func (o *Record) Type() string

Type returns the type of the record.

func (*Record) UpdatedAt

func (o *Record) UpdatedAt() string

UpdatedAt returns the updated at time of the record.

type RecordQueryOptions

type RecordQueryOptions struct {
	ID                   string
	IDIn                 []string
	ParentID             string
	Type                 string
	Path                 string
	PathStartsWith       string
	CreatedAtLessThan    string
	CreatedAtGreaterThan string
	UpdatedAtLessThan    string
	UpdatedAtGreaterThan string
	Columns              []string
	Offset               int
	Limit                int
	SortOrder            string
	OrderBy              string
	CountOnly            bool
	WithSoftDeleted      bool
}

RecordQueryOptions defines the available filters and options for record queries.

type Store

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

Store provides a hierarchical file-system-like storage in a SQL database.

func NewStore

func NewStore(opts NewStoreOptions) (*Store, error)

NewStore creates a new file store instance with the provided options.

func (*Store) EnableDebug

func (st *Store) EnableDebug(debug bool)

EnableDebug enables or disables SQL debug logging.

func (*Store) MigrateDown added in v1.4.0

func (store *Store) MigrateDown(ctx context.Context, tx ...*sql.Tx) error

MigrateDown drops the sqlfilestore table

func (*Store) MigrateUp added in v1.4.0

func (store *Store) MigrateUp(ctx context.Context, tx ...*sql.Tx) error

MigrateUp creates the database table if it doesn't exist and ensures a root directory record is present.

func (*Store) RecordCount

func (st *Store) RecordCount(ctx context.Context, options RecordQueryOptions) (int64, error)

RecordCount returns the count of records matching the provided query options.

func (*Store) RecordCreate

func (store *Store) RecordCreate(ctx context.Context, record *Record) error

RecordCreate inserts a new record into the database.

func (*Store) RecordDelete

func (store *Store) RecordDelete(ctx context.Context, record *Record) error

RecordDelete permanently removes a record from the database.

func (*Store) RecordDeleteByID

func (store *Store) RecordDeleteByID(ctx context.Context, id string) error

RecordDeleteByID permanently deletes a record by its ID.

func (*Store) RecordFindByID

func (store *Store) RecordFindByID(ctx context.Context, id string, options RecordQueryOptions) (*Record, error)

RecordFindByID finds a single record by its ID.

func (*Store) RecordFindByPath

func (store *Store) RecordFindByPath(ctx context.Context, path string, options RecordQueryOptions) (*Record, error)

RecordFindByPath finds a single record by its path.

func (*Store) RecordList

func (store *Store) RecordList(ctx context.Context, options RecordQueryOptions) ([]Record, error)

RecordList retrieves a list of records matching the provided query options.

func (*Store) RecordRecalculatePath

func (store *Store) RecordRecalculatePath(ctx context.Context, record *Record, parentRecord *Record) error

RecordRecalculatePath updates the path of a record and all its children after a rename or move operation.

func (*Store) RecordSoftDelete

func (store *Store) RecordSoftDelete(ctx context.Context, record *Record) error

RecordSoftDelete marks a record as deleted by setting the deleted_at timestamp.

func (*Store) RecordSoftDeleteByID

func (store *Store) RecordSoftDeleteByID(ctx context.Context, id string) error

RecordSoftDeleteByID finds a record by ID and marks it as soft deleted.

func (*Store) RecordUpdate

func (store *Store) RecordUpdate(ctx context.Context, record *Record) error

RecordUpdate updates an existing record in the database.

Jump to

Keyboard shortcuts

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