Documentation
¶
Overview ¶
Package store implements sync82's SQLite-backed persistence layer: projects (each optionally holding subprojects), overwrite-style documents, append-only entries, and search across both: by words or phrase through FTS5 indexes that ignore case and the accents of Latin letters, or by a case-insensitive substring. Manager caches one *Store per vault path so repeated calls against the same vault reuse a connection pool; Open handles per-vault schema migrations and connection setup. Every *Store method is safe for concurrent use. Lookup failures wrap ErrNotFound, naming collisions wrap ErrAlreadyExists, and Open failures wrap ErrOpenFailed; check them with errors.Is. Messages of all errors except ErrOpenFailed contain no filesystem paths.
Index ¶
- Variables
- func HasSearchTerms(query string) bool
- type ArchiveResult
- type ArchiveSummary
- type Entry
- type EntrySection
- type EntryStats
- type KindMetadata
- type KindStorage
- type KindWrite
- type Manager
- type Project
- type ProjectNode
- type SearchInfo
- type SearchMode
- type SearchOptions
- type SearchResult
- type SearchScope
- type Store
- func (s *Store) AppendEntry(ctx context.Context, project, subproject, kind, entryDate, body string) error
- func (s *Store) ArchiveEntries(ctx context.Context, project, subproject, kind, cutoff string, ...) (ArchiveResult, error)
- func (s *Store) Close() error
- func (s *Store) CreateProject(ctx context.Context, name string, parentID *int64) (*Project, error)
- func (s *Store) DeleteEntry(ctx context.Context, project, subproject, kind string, id int64) error
- func (s *Store) DeleteKind(ctx context.Context, project, subproject, kind string) error
- func (s *Store) DeleteProject(ctx context.Context, name string) error
- func (s *Store) DeleteProjectExpecting(ctx context.Context, name string, expected int) error
- func (s *Store) DeleteSubproject(ctx context.Context, parentName, subName string) error
- func (s *Store) EnsureProject(ctx context.Context, project, subproject string) (proj *Project, created bool, err error)
- func (s *Store) EntryStats(ctx context.Context, project, subproject, kind string) (EntryStats, error)
- func (s *Store) FindProjectByName(ctx context.Context, name string, parentID *int64) (*Project, error)
- func (s *Store) KindExists(ctx context.Context, project, subproject, kind string) (bool, error)
- func (s *Store) KindMode(ctx context.Context, project, subproject, kind string) (KindStorage, error)
- func (s *Store) KindModes(ctx context.Context, project, subproject string) (map[string]KindStorage, error)
- func (s *Store) ListArchivable(ctx context.Context, project, subproject, kind, cutoff string) ([]Entry, error)
- func (s *Store) ListKinds(ctx context.Context, project, subproject string, includeArchived bool) ([]string, error)
- func (s *Store) ListSubprojects(ctx context.Context, parentID int64) ([]Project, error)
- func (s *Store) ListTopLevelProjects(ctx context.Context) ([]Project, error)
- func (s *Store) Metadata(ctx context.Context, project, subproject, kind string) (KindMetadata, error)
- func (s *Store) ProjectExists(ctx context.Context, project, subproject string) (bool, error)
- func (s *Store) ProjectTree(ctx context.Context) ([]ProjectNode, error)
- func (s *Store) PromoteAllSubprojects(ctx context.Context, parentName string) ([]string, error)
- func (s *Store) PromoteSubproject(ctx context.Context, parentName, subName string) error
- func (s *Store) PromoteSubprojectsAndDelete(ctx context.Context, parentName string) ([]string, error)
- func (s *Store) ReadContent(ctx context.Context, project, subproject, kind string) (content string, ok bool, err error)
- func (s *Store) ReadDocument(ctx context.Context, project, subproject, kind string) (content string, ok bool, err error)
- func (s *Store) ReadEntries(ctx context.Context, project, subproject, kind string, includeArchived bool) ([]Entry, error)
- func (s *Store) ReadEntriesSince(ctx context.Context, project, subproject, kind, since string, maxEntries int) ([]Entry, error)
- func (s *Store) ReadEntry(ctx context.Context, project, subproject, kind string, id int64) (Entry, error)
- func (s *Store) RenameProject(ctx context.Context, project, subproject, newName string) error
- func (s *Store) ReplaceAllEntries(ctx context.Context, project, subproject, kind string, sections []EntrySection) error
- func (s *Store) ReplaceArchivedEntries(ctx context.Context, project, subproject, kind string, sections []EntrySection) error
- func (s *Store) SearchText(ctx context.Context, opts SearchOptions) ([]SearchResult, SearchInfo, error)
- func (s *Store) SupersedeEntry(ctx context.Context, project, subproject, kind string, id int64, ...) (int64, error)
- func (s *Store) UpdateEntry(ctx context.Context, project, subproject, kind string, id int64, body string, ...) error
- func (s *Store) WriteDocument(ctx context.Context, project, subproject, kind, content string) error
- func (s *Store) WriteKinds(ctx context.Context, project, subproject string, writes []KindWrite) error
Constants ¶
This section is empty.
Variables ¶
var ErrAlreadyExists = errors.New("already exists")
ErrAlreadyExists is wrapped when an operation would create a naming collision, for example promoting a subproject to a name already used at the vault root.
var ErrEntryArchived = errors.New("entry is archived")
ErrEntryArchived is wrapped by SupersedeEntry when the entry to supersede is archived.
var ErrManagerClosed = errors.New("store manager is closed")
ErrManagerClosed is returned by Get once Close has been called, so a goroutine still running during shutdown cannot open a connection that Close would never release.
var ErrNoSearchTerms = errors.New("the query has no words to search for")
ErrNoSearchTerms is returned by SearchText when a words or phrase query holds no letter or number to search for.
var ErrNotFound = errors.New("not found")
ErrNotFound is wrapped by any lookup that fails to find its target (project, subproject, document kind, or entries kind). Check for it with errors.Is; the error message describes what was not found without including filesystem paths.
var ErrOpenFailed = errors.New("could not open vault")
ErrOpenFailed is wrapped by Open when the vault directory, file, database connection or migration step fails. Unlike every other store error, its messages embed a raw filesystem path, so callers that return errors to remote clients should detect it with errors.Is and substitute a generic message.
var ErrSchemaTooNew = errors.New("the vault's schema is newer than this sync82 supports; upgrade sync82")
ErrSchemaTooNew is wrapped, together with ErrOpenFailed, when the vault's schema version is newer than the latest one this binary knows: a newer sync82 has upgraded the vault, and this one refuses to read or write it.
var ErrStorageConflict = errors.New("storage conflict")
ErrStorageConflict is wrapped by WriteKinds when a write would store a kind the other way it is stored already: as a document while it has entries, or as entries while it has a document. The message names the kind and its current storage.
var ErrSubprojectCount = errors.New("subproject count changed")
ErrSubprojectCount is wrapped by DeleteProjectExpecting when the project has a different number of subprojects than the caller expected. The message gives the current count.
var ErrVaultNotFound = errors.New("vault not found")
ErrVaultNotFound is returned by Manager.GetExisting when no vault file exists at the requested path. Its message holds no path; callers know it.
Functions ¶
func HasSearchTerms ¶ added in v1.1.0
HasSearchTerms reports whether query holds at least one searchable word for the words and phrase search modes, that is, at least one letter or number.
Types ¶
type ArchiveResult ¶
type ArchiveResult struct {
Archived int
OldestDate string
NewestDate string
Kept int
NoDate int
SummaryID int64
}
ArchiveResult summarizes the outcome of an ArchiveEntries call: Archived is the number of entries archived by the call, OldestDate and NewestDate the range of their dates ("" when none was archived), Kept the number of non-archived entries remaining afterwards (a summary entry included), and NoDate how many of those are undated. SummaryID is the id of the summary entry, or 0 when none was added.
type ArchiveSummary ¶ added in v1.1.0
type ArchiveSummary func(archived ArchiveResult) (entryDate, body string, err error)
ArchiveSummary builds the summary entry ArchiveEntries adds after archiving: given the archived range (Archived, OldestDate and NewestDate set), it returns the entry's date ("" for undated) and body. An error aborts the whole call. It runs inside the transaction, which holds the Store's only connection: it must not call any *Store method.
type Entry ¶
type Entry struct {
ID int64
EntryDate string // "", if undated
Body string
Archived bool
CreatedAt string
}
Entry is a single row of an append-only log. ID is the row's identifier, unique within the vault, stable for the life of the row (rewriting the whole kind, or importing it, creates new rows) and never given to another row, even after this one is deleted. EntryDate is empty when the entry is undated.
type EntrySection ¶
type EntrySection struct {
Date string // "YYYY-MM-DD", empty for undated content
Body string
// Preamble marks undated content that precedes the first dated section
// (such as a title). It is stored with position preamblePosition so it
// reads back first instead of after every dated entry.
Preamble bool
}
EntrySection is a single dated or undated chunk of append-only content, such as one "## YYYY-MM-DD" section of a log. The store persists already-parsed sections and does not split raw text itself.
type EntryStats ¶ added in v1.1.0
EntryStats summarizes the non-archived entries of a kind: Dated counts the dated ones (those ReadEntriesSince filters with since and maxEntries), Undated the undated ones other than a preamble, and LatestDate is the newest entry date ("" when none is dated).
type KindMetadata ¶
KindMetadata describes the size and freshness of a kind's content. SizeBytes is the content length in bytes, EstimatedTokens a rough estimate (SizeBytes / 4), and LastModified the update date of a document, or the creation date of the newest non-archived entry of a log (of the newest entry when all are archived): editing an entry does not change it.
type KindStorage ¶
type KindStorage string
KindStorage names the table a kind's data lives in for a project.
const ( // KindStorageNone means the kind has no data yet. KindStorageNone KindStorage = "" // KindStorageDocument means the kind is a single overwrite-style // documents row. KindStorageDocument KindStorage = "document" // KindStorageEntries means the kind is a log of entries rows // (archived or not). KindStorageEntries KindStorage = "entries" )
type KindWrite ¶
type KindWrite struct {
Kind string
Document *string
Sections []EntrySection
Archived bool
Append bool
}
KindWrite is one kind's new content in a WriteKinds batch: Document for an overwrite-style kind, or Sections replacing its entries (the non-archived ones, or the archived ones when Archived is set). With Append, Sections are added as new non-archived entries after the existing ones instead, as AppendEntry adds one. Document takes precedence when non-nil.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager caches one Store per vault path, so repeated calls against the same vault reuse one connection pool instead of reopening the database and re-running the migration check each time. A process may use several vault paths, hence one Store per path. A Manager is safe for concurrent use.
func (*Manager) Close ¶
Close closes every cached Store, empties the cache and marks the Manager closed, so later Get calls fail with ErrManagerClosed. It returns the first error reported while closing a Store, after attempting to close all of them.
func (*Manager) Get ¶
Get returns the Store for path, opening and caching it on first use. path is made absolute first, so equivalent spellings share one Store. It returns ErrManagerClosed once Close has run, and any error from Open (wrapping ErrOpenFailed) when the vault cannot be opened.
Open runs outside m.mu because it performs file I/O and migrations; a slow first open of one vault must not block calls against other vaults. The lock only guards the cache lookup and the reconciliation after Open returns.
func (*Manager) GetExisting ¶
GetExisting is Get for callers that must not create a vault: when no file exists at path it returns ErrVaultNotFound, whose message holds no path, instead of creating an empty vault there. Other errors are those of Get.
type Project ¶
Project is a row of the projects table: a top-level project (ParentID not valid) or a subproject (ParentID holds the parent's ID). CreatedAt is an RFC 3339 timestamp.
type ProjectNode ¶ added in v1.2.0
ProjectNode is one top-level project of a ProjectTree with the names of its subprojects, in name order.
type SearchInfo ¶ added in v1.3.0
SearchInfo describes how a SearchText call ran. Truncated reports whether the scan stopped at maxScannedRows or maxScannedBytes, in which case later matches are missing. Substring reports whether a words or phrase search fell back to matching its words as substrings, in reading order.
type SearchMode ¶ added in v1.1.0
type SearchMode string
SearchMode selects how SearchText matches a query.
const ( SearchWords SearchMode = "words" SearchPhrase SearchMode = "phrase" SearchExact SearchMode = "exact" )
The search modes. SearchWords finds rows holding every word of the query and SearchPhrase rows holding the words in that order, both through the full-text indexes, ignoring case and Latin diacritics, ranked by relevance. SearchExact finds rows holding the query as a literal, case-insensitive substring, in reading order.
type SearchOptions ¶ added in v1.1.0
type SearchOptions struct {
Query string
Mode SearchMode
Scope SearchScope
Kinds []string
Since string
Until string
Offset int
Limit int
ContextLines int
}
SearchOptions describes a SearchText call. Mode defaults to SearchWords when empty. Kinds, when not empty, limits the search to those kinds (normalized names). Since and Until ("YYYY-MM-DD", inclusive), when set, limit the search to dated entries in that range; documents and undated entries are then left out. Offset and Limit select the page of matching lines (SearchText returns up to Limit+1 of them, starting at Offset); ContextLines, when positive, adds that many lines before and after each match.
type SearchResult ¶
type SearchResult struct {
Project string
Subproject string
Kind string
EntryID int64
EntryDate string
LineNumber int
Line string
ContextBefore []string
ContextAfter []string
}
SearchResult is a single matching line within a document or entry. Project is the top-level project name and Subproject the subproject name (empty for a top-level project). For an entry, EntryID is its id (0 for a document) and EntryDate its date ("" if undated); LineNumber is the 1-based line within the document or entry body. Line is the matching line, and ContextBefore and ContextAfter hold the surrounding lines when context was requested.
type SearchScope ¶
SearchScope narrows a search to a project (and optionally a specific subproject). An empty Project means the whole vault; a Project with an empty Subproject means that project plus all of its subprojects.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is a SQLite-backed vault: one physical file holds every project's documents and entries. A Store is safe for concurrent use by multiple goroutines.
func Open ¶
Open opens (creating if necessary) the SQLite database at path and applies pending schema migrations. ctx bounds the initial ping and the migration, so a cancelled or expired context stops Open from waiting on a slow disk or filesystem mount.
It returns an error wrapping ErrOpenFailed when path contains '?' or '#', when the vault directory or file cannot be created, or when opening, pinging or migrating the database fails (including a vault whose schema is newer than this binary supports).
SQLite pragmas are connection-scoped, not database-scoped, so foreign_keys and journal_mode are set via DSN query parameters (modernc.org/sqlite applies "_pragma" params to every new physical connection the pool creates) rather than a one-time PRAGMA statement — that guarantees every connection enforces foreign keys and uses WAL, including a connection database/sql reopens after closing one.
The pool holds a single connection, so the operations of one Store run one at a time and only other processes contend for the file lock.
func (*Store) AppendEntry ¶
func (s *Store) AppendEntry(ctx context.Context, project, subproject, kind, entryDate, body string) error
AppendEntry inserts one new, non-archived entry with the given date (empty for undated) and body at the next insertion position for its (project, kind) pair. The position is computed by a subquery in the same INSERT statement, so concurrent appends cannot read the same position. It returns an error wrapping ErrNotFound when the project or subproject does not exist, or a database error.
func (*Store) ArchiveEntries ¶
func (s *Store) ArchiveEntries(ctx context.Context, project, subproject, kind, cutoff string, summary ArchiveSummary) (ArchiveResult, error)
ArchiveEntries marks every non-archived, dated entry older than cutoff (format "YYYY-MM-DD") as archived. Undated entries are never archived. When summary is not nil and at least one entry is archived, the entry it builds is appended as a new, non-archived entry. Everything happens in one transaction, so a failure leaves the entries unchanged. It returns the counts as an ArchiveResult. It returns an error wrapping ErrNotFound when the project or subproject does not exist, summary's error, or a database error.
func (*Store) Close ¶
Close closes the underlying database connection pool and returns any error reported by the driver.
func (*Store) CreateProject ¶
CreateProject inserts a new project row named name (normalized), top-level when parentID is nil and otherwise a child of parentID. It returns the created Project, an error wrapping ErrAlreadyExists when a project with that name already exists in the same scope, one wrapping ErrNotFound when parentID names no project (it was deleted meanwhile), or a database error. The existence of parentID is checked by the foreign key.
func (*Store) DeleteEntry ¶ added in v1.1.0
DeleteEntry deletes the entry with the given id, archived or not. It returns an error wrapping ErrNotFound when the project or subproject does not exist or no such entry belongs to (project, kind), or a database error.
func (*Store) DeleteKind ¶
DeleteKind deletes every row (document and entries, archived or not) of a kind in one transaction, so a kind is never left half-deleted. The store does not protect any kind from deletion. It returns an error wrapping ErrNotFound when the project or subproject does not exist or the kind has no rows, or a database error.
func (*Store) DeleteProject ¶
DeleteProject deletes a top-level project by name, cascading to its subprojects, documents and entries via ON DELETE CASCADE. It returns an error wrapping ErrNotFound when no such project exists, or a database error.
func (*Store) DeleteProjectExpecting ¶ added in v1.3.0
DeleteProjectExpecting deletes the top-level project name as DeleteProject does, in one transaction that first checks that it has exactly expected subprojects. It returns an error wrapping ErrNotFound when no such project exists, an error wrapping ErrSubprojectCount, with nothing deleted, when the count differs, or a database error.
func (*Store) DeleteSubproject ¶
DeleteSubproject deletes the subproject subName of parentName, cascading to its documents and entries, in one transaction that also resolves both names. It returns an error wrapping ErrNotFound when the parent or subproject does not exist, or a database error.
func (*Store) EnsureProject ¶
func (s *Store) EnsureProject(ctx context.Context, project, subproject string) (proj *Project, created bool, err error)
EnsureProject returns the project or subproject, creating it (and its parent project when missing) if needed. subproject may be empty for a top-level project. created reports whether the leaf (project or subproject) was created by this call; it does not report whether a missing parent was also created. It returns a database error on failure.
The check-then-create sequence is not a single transaction, so concurrent calls for the same new name can both attempt the insert. The UNIQUE index decides the winner, and createOrRecoverExisting turns the loser's constraint violation into the existing row.
func (*Store) EntryStats ¶ added in v1.1.0
func (s *Store) EntryStats(ctx context.Context, project, subproject, kind string) (EntryStats, error)
EntryStats returns the EntryStats of (project, kind), all zero for a kind with no entries. It returns an error wrapping ErrNotFound when the project or subproject does not exist, or a database error.
func (*Store) FindProjectByName ¶
func (s *Store) FindProjectByName(ctx context.Context, name string, parentID *int64) (*Project, error)
FindProjectByName looks up a project by name within the given parent scope (parentID nil means top-level). The name is normalized. It returns (nil, nil) when no matching row exists, and a database error otherwise.
func (*Store) KindExists ¶
KindExists reports whether a kind has any data for the project: a documents row (even with empty content) or at least one entries row, archived or not. It checks existence only, never loading the content. Errors are those of KindMode.
func (*Store) KindMode ¶
func (s *Store) KindMode(ctx context.Context, project, subproject, kind string) (KindStorage, error)
KindMode reports which table holds a kind's data for the project, or KindStorageNone when it has none. A kind present in both tables reports KindStorageDocument, the table ReadContent reads first. It returns an error wrapping ErrNotFound when the project or subproject does not exist, or a database error.
func (*Store) KindModes ¶ added in v1.2.0
func (s *Store) KindModes(ctx context.Context, project, subproject string) (map[string]KindStorage, error)
KindModes returns the KindStorage of every kind with data in the project, in one query: KindStorageDocument for a kind with a documents row (even when it also has entries, as KindMode reports it), otherwise KindStorageEntries for a kind with entries rows, archived or not. It returns an error wrapping ErrNotFound when the project or subproject does not exist, or a database error.
func (*Store) ListArchivable ¶ added in v1.1.0
func (s *Store) ListArchivable(ctx context.Context, project, subproject, kind, cutoff string) ([]Entry, error)
ListArchivable returns the entries ArchiveEntries would archive with the same cutoff: non-archived, dated entries older than cutoff, in reading order. It returns an error wrapping ErrNotFound when the project or subproject does not exist, or a database error.
func (*Store) ListKinds ¶
func (s *Store) ListKinds(ctx context.Context, project, subproject string, includeArchived bool) ([]string, error)
ListKinds returns every kind known for the project, the union of document kinds and distinct entries kinds, sorted by name. A kind whose entries are all archived is included only when includeArchived is true. It returns an error wrapping ErrNotFound when the project or subproject does not exist, or a database error.
func (*Store) ListSubprojects ¶
ListSubprojects returns every project whose parent is parentID, sorted by name. It returns a database error on failure.
func (*Store) ListTopLevelProjects ¶
ListTopLevelProjects returns every project with no parent, sorted by name. It returns a database error on failure.
func (*Store) Metadata ¶
func (s *Store) Metadata(ctx context.Context, project, subproject, kind string) (KindMetadata, error)
Metadata computes KindMetadata for a document or entries kind. For a document it uses the content size and update date; for entries it sums the sizes of the non-archived bodies and uses the latest creation date of the non-archived entries, or of all entries when every one is archived (size 0), so a kind KindExists reports always has metadata. Sizes use length(CAST(x AS BLOB)) because SQLite's length() counts characters, not bytes, for TEXT values. It returns an error wrapping ErrNotFound when the project does not exist or the kind has no document and no entries, or a database error.
func (*Store) ProjectExists ¶
ProjectExists reports whether the (project, subproject) pair exists. subproject may be empty to check the top-level project itself. It returns an error only for database failures.
func (*Store) ProjectTree ¶ added in v1.2.0
func (s *Store) ProjectTree(ctx context.Context) ([]ProjectNode, error)
ProjectTree returns every top-level project with its subprojects, both in name order, read in one query. Subprojects is empty, not nil, for a project without any. It returns a database error on failure.
func (*Store) PromoteAllSubprojects ¶
PromoteAllSubprojects promotes every subproject of parentName to the vault root in a single transaction: either all of them are promoted or none is. The parent and its subprojects are read inside that transaction, so the promoted set is the one present when the writes are applied. It returns the promoted names (nil when there are none). It returns an error wrapping ErrNotFound when the parent does not exist, an error wrapping ErrAlreadyExists when any name collides with a top-level project (rolling the whole batch back), or a database error.
func (*Store) PromoteSubproject ¶
PromoteSubproject moves the subproject subName of parentName to the vault root as a top-level project, in one transaction that also resolves both names. It returns an error wrapping ErrNotFound when the parent or subproject does not exist, an error wrapping ErrAlreadyExists when a top-level project with that name exists, or a database error.
func (*Store) PromoteSubprojectsAndDelete ¶ added in v1.1.1
func (s *Store) PromoteSubprojectsAndDelete(ctx context.Context, parentName string) ([]string, error)
PromoteSubprojectsAndDelete moves every subproject of the top-level project parentName to the vault root, as PromoteAllSubprojects does, and then deletes parentName with its own documents and entries, all in one transaction: either both happen or nothing changes. It returns the promoted names (nil when there are none). It returns an error wrapping ErrNotFound when the project does not exist, an error wrapping ErrAlreadyExists when a subproject name collides with a top-level project, or a database error.
func (*Store) ReadContent ¶
func (s *Store) ReadContent(ctx context.Context, project, subproject, kind string) (content string, ok bool, err error)
ReadContent returns the readable content of a kind, from whichever table holds it. A document takes precedence; otherwise the bodies of the non-archived entries are joined with a blank line between them. ok is false when the kind has neither a document nor non-archived entries. It returns an error wrapping ErrNotFound when the project or subproject does not exist, or a database error.
func (*Store) ReadDocument ¶
func (s *Store) ReadDocument(ctx context.Context, project, subproject, kind string) (content string, ok bool, err error)
ReadDocument returns the raw content of the overwrite-style document of the given kind for project/subproject. ok is false, with no error, when the document row does not exist. It returns an error wrapping ErrNotFound when the project or subproject does not exist, or a database error.
func (*Store) ReadEntries ¶
func (s *Store) ReadEntries(ctx context.Context, project, subproject, kind string, includeArchived bool) ([]Entry, error)
ReadEntries returns entries for (project, kind) in reading order: a preamble first, then dated entries by date, then other undated entries, ties broken by insertion position. Archived entries are excluded unless includeArchived is true. A kind with no entries yields an empty slice and no error. It returns an error wrapping ErrNotFound when the project or subproject does not exist, or a database error.
func (*Store) ReadEntriesSince ¶
func (s *Store) ReadEntriesSince(ctx context.Context, project, subproject, kind, since string, maxEntries int) ([]Entry, error)
ReadEntriesSince returns non-archived entries for (project, kind), filtered in SQL so the full history is never loaded just to return recent entries.
Both filters apply to dated entries only; undated entries (a preamble, undated notes) are always kept, as in ArchiveEntries. since, if non-empty (format "YYYY-MM-DD"), keeps only dated entries on or after it. maxEntries, if > 0, then keeps only the most recent maxEntries of those dated entries. The result is in the same reading order ReadEntries uses. It returns an error wrapping ErrNotFound when the project or subproject does not exist, or a database error.
func (*Store) ReadEntry ¶ added in v1.1.0
func (s *Store) ReadEntry(ctx context.Context, project, subproject, kind string, id int64) (Entry, error)
ReadEntry returns the entry with the given id, archived or not, when it belongs to (project, kind). It returns an error wrapping ErrNotFound when the project or subproject does not exist or no such entry belongs to it, or a database error.
func (*Store) RenameProject ¶
RenameProject renames a top-level project (subproject == "") or a specific subproject in place to newName (normalized), in one transaction that also resolves the names. It returns an error wrapping ErrNotFound when the project or subproject does not exist, an error wrapping ErrAlreadyExists when a sibling in the same scope already has newName, or a database error. Only the database is changed.
func (*Store) ReplaceAllEntries ¶
func (s *Store) ReplaceAllEntries(ctx context.Context, project, subproject, kind string, sections []EntrySection) error
ReplaceAllEntries atomically replaces every non-archived entries row for (project, kind) with the given sections, in order. Archived rows are left untouched. The result reads the same as appending the sections one by one with AppendEntry, except that a Preamble section is placed first. It returns an error wrapping ErrNotFound when the project or subproject does not exist, or a database error.
func (*Store) ReplaceArchivedEntries ¶
func (s *Store) ReplaceArchivedEntries(ctx context.Context, project, subproject, kind string, sections []EntrySection) error
ReplaceArchivedEntries atomically replaces every archived entries row for (project, kind) with the given sections, stored as archived. Non-archived rows are left untouched. It returns an error wrapping ErrNotFound when the project or subproject does not exist, or a database error.
func (*Store) SearchText ¶
func (s *Store) SearchText(ctx context.Context, opts SearchOptions) ([]SearchResult, SearchInfo, error)
SearchText searches the documents and non-archived entries in scope and returns their matching lines. In SearchWords and SearchPhrase modes the full-text indexes select the rows, ordered by relevance (bm25), then by project, subproject, kind and reading order; a line matches when it holds one of the query's words (words mode) or the whole phrase (phrase mode), and a row whose phrase spans several lines reports the lines holding any of its words. In SearchExact mode the query is a literal, case-insensitive substring (Unicode-aware: "DECISÃO" matches "decisão") and matches are ordered by project, subproject, kind, then reading order.
When a words or phrase search finds no row and the query holds a rune outside the scripts the index is known to tokenize and fold as foldText does (see prefilterSafe), the rows are selected again with every word as a substring of the folded text, kept when their tokens hold the words as the index would match them (rowHasTerms), and the lines are matched as before, in reading order as in SearchExact mode. SearchInfo.Substring reports it.
It returns the matching lines skipping the first opts.Offset, up to opts.Limit+1 of them: the extra one lets the caller detect that more results exist (a negative Offset or Limit counts as 0). Lines are split on "\n" with a trailing "\r" removed, so CRLF content reads like LF. The SearchInfo reports whether the scan stopped at maxScannedRows or maxScannedBytes, in which case later matches are missing, and whether the substring fallback ran. It returns an error wrapping ErrNotFound when the scoped project or subproject does not exist, an error wrapping ErrNoSearchTerms when a words or phrase query has no letter or number, or a database error.
func (*Store) SupersedeEntry ¶ added in v1.1.0
func (s *Store) SupersedeEntry(ctx context.Context, project, subproject, kind string, id int64, entryDate, body string, mark func(oldBody string, newID int64) string) (int64, error)
SupersedeEntry appends a new, non-archived entry with entryDate (empty for undated) and body, as AppendEntry does, and replaces the body of the entry with the given id by mark(oldBody, newID), all in one transaction. mark runs inside the transaction, which holds the Store's only connection: it must not call any *Store method. It returns the new entry's id. It returns an error wrapping ErrNotFound when the project or subproject does not exist or no such entry belongs to (project, kind), an error wrapping ErrEntryArchived, with nothing changed, when the entry is archived, or a database error.
func (*Store) UpdateEntry ¶ added in v1.1.0
func (s *Store) UpdateEntry(ctx context.Context, project, subproject, kind string, id int64, body string, entryDate *string) error
UpdateEntry replaces the body of the entry with the given id, keeping its position and archived flag. When entryDate is non-nil it also sets the entry's date ("" for undated); otherwise the date is kept. It returns an error wrapping ErrNotFound when the project or subproject does not exist or no such entry belongs to (project, kind), or a database error.
func (*Store) WriteDocument ¶
WriteDocument sets the content of the overwrite-style document of the given kind for project/subproject, inserting it when it does not exist yet. The names are normalized. It returns an error wrapping ErrNotFound when the project or subproject does not exist, or a database error. The project is resolved and the document upserted in one transaction.
func (*Store) WriteKinds ¶
func (s *Store) WriteKinds(ctx context.Context, project, subproject string, writes []KindWrite) error
WriteKinds applies every write to (project, subproject) in one transaction: either all of them take effect or none does. Kind names are normalized. A kind keeps the storage it has: a document write to a kind that has entries, or an entries write to a kind that has a document, is refused, including when an earlier write of the same batch gave the kind its storage. It returns an error wrapping ErrNotFound when the project or subproject does not exist, one wrapping ErrStorageConflict for such a write, or a database error.