database

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Sep 16, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package database reads and writes ZenNotes databases: a `<Name>.base/` folder holding `data.csv`, a `schema.json` sidecar and record-page notes. Everything is composed from generic vault-file IO, the same composition the web and desktop remote clients use, so an edit made here is byte-identical to one made in the app's grid.

Index

Constants

View Source
const (
	// FormDirSuffix marks a database folder.
	FormDirSuffix = ".base"
	// FormDataFile and FormSchemaFile are the fixed names inside it.
	FormDataFile   = "data.csv"
	FormSchemaFile = "schema.json"
	// EmptyGroup is the board column for rows whose group-by cell is empty.
	EmptyGroup = "__empty__"
)
View Source
const SidecarSuffix = ".base.json"

SidecarSuffix follows a loose `.csv` to name its schema file: `Books.csv` keeps its schema in `Books.csv.base.json`.

Variables

View Source
var FieldTypes = []string{"text", "number", "checkbox", "date", "select", "multiSelect", "note", "noteMulti"}

FieldTypes lists the field types in the order the desktop offers them.

View Source
var OptionColors = []string{"red", "orange", "amber", "green", "teal", "sky", "blue", "indigo", "violet", "pink"}

OptionColors are the palette tokens the desktop assigns to options.

Functions

func CSVPathForFormDir

func CSVPathForFormDir(formDir string) string

CSVPathForFormDir is `<dir>/data.csv`.

func FieldTypeLabel

func FieldTypeLabel(t string) string

FieldTypeLabel is the display name of a field type.

func FilterNeedsValue

func FilterNeedsValue(op string) bool

FilterNeedsValue is false for operators that take no value.

func FilterOpLabel

func FilterOpLabel(op string) string

FilterOpLabel is the operator's display text.

func FilterOps

func FilterOps(fieldType string) []string

FilterOps lists the operators that make sense for a field type.

func FormDirContaining

func FormDirContaining(relPath string) string

FormDirContaining is the `.base` folder a path lives in, or "".

func FormDirFromCSVPath

func FormDirFromCSVPath(csvPath string) string

FormDirFromCSVPath is the database folder for a `data.csv` path, or "".

func GenID

func GenID() string

GenID mints a lowercase v4 UUID, the row and field identity the app uses.

func HasRecordPages

func HasRecordPages(csvPath string) bool

HasRecordPages is true when a database can own record pages: only `.base` folders have a pages directory.

func IsCheckboxTrue

func IsCheckboxTrue(cell string) bool

IsCheckboxTrue reads a checkbox cell.

func IsFormDirName

func IsFormDirName(nameOrPath string) bool

IsFormDirName is true for a `<Name>.base` folder name or path.

func IsLooseCSVPath

func IsLooseCSVPath(rel string) bool

IsLooseCSVPath is true for a `.csv` outside any `.base` folder.

func IsNoteType

func IsNoteType(t string) bool

IsNoteType is true for the two wikilink-backed types.

func IsSelectType

func IsSelectType(t string) bool

IsSelectType is true for the two option-backed types.

func IsSidecarPath

func IsSidecarPath(rel string) bool

IsSidecarPath is true for a loose CSV's schema file.

func JoinMultiSelect

func JoinMultiSelect(values []string) string

JoinMultiSelect composes a multiSelect cell.

func JoinNoteLinks(targets []string) string

JoinNoteLinks composes a note cell from targets: `[[A]] [[B]]`.

func ParseCSV

func ParseCSV(text string) [][]string

ParseCSV parses RFC 4180 text into a grid. Blank lines are dropped; a BOM is stripped.

func SchemaPathFor

func SchemaPathFor(csvPath string) string

SchemaPathFor is `<dir>/schema.json` for a `.base` folder's data.csv, `<file>.csv.base.json` for a loose CSV, or "" for anything else.

func SerializeCSV

func SerializeCSV(rows [][]string) string

SerializeCSV renders a grid as RFC 4180 text with LF newlines and a trailing newline.

func SerializeRows

func SerializeRows(rows []Row, fields []Field) string

SerializeRows renders rows back to CSV text, header from the field names in field order.

func SplitMultiSelect

func SplitMultiSelect(cell string) []string

SplitMultiSelect splits a multiSelect cell ("a, b") into values.

func SplitNoteLinks(cell string) []string

SplitNoteLinks extracts the wikilink targets of a note cell, in order.

func Stringify

func Stringify(o *Object) (string, error)

Stringify renders like `JSON.stringify(value, null, 2)`.

func TitleFromCSVPath

func TitleFromCSVPath(csvPath string) string

TitleFromCSVPath is the display title from a data.csv path.

func TitleFromDir

func TitleFromDir(nameOrPath string) string

TitleFromDir is the display title of a database folder.

Types

type BoardColumn

type BoardColumn struct {
	Key  string
	Rows []Row
}

BoardColumn is one column of a board view.

func BoardColumns

func BoardColumns(rows []Row, groupField Field, optionOrder []string) []BoardColumn

BoardColumns groups rows by a select field's value, an EmptyGroup column appended for rows whose cell is empty or references a removed option.

type CSVLister

type CSVLister interface {
	ListCSVFiles() ([]string, error)
}

CSVLister is implemented by backends that can find loose `.csv` files; without it only `.base` folders are databases.

type Doc

type Doc struct {
	// Path is the vault-relative `data.csv` path: the database's identity.
	Path  string
	Title string
	// Sidecar is the normalized schema.json with pages made vault-relative.
	Sidecar      *Object
	IDFieldID    string
	Fields       []Field
	Views        []View
	ActiveViewID string
	// Pages maps row id to the record page's vault-relative path.
	Pages map[string]string
	Rows  []Row
	// PageHasContent says whether a row's page has body beyond its heading.
	PageHasContent map[string]bool
}

Doc is a fully hydrated database.

func (*Doc) ActiveView

func (d *Doc) ActiveView() *View

ActiveView is the view the sidecar marks active, else the first.

func (*Doc) AddField

func (d *Doc) AddField(name, typ string) (Field, error)

AddField appends a field and shows it in every table view.

func (*Doc) AddRow

func (d *Doc) AddRow() Row

AddRow appends an empty row and returns it.

func (*Doc) AddView

func (d *Doc) AddView(typ string) (View, error)

AddView appends a table or board view and makes it active.

func (*Doc) ComposePageBody

func (d *Doc) ComposePageBody(row Row, body string) string

ComposePageBody composes a record page: the row's properties as flat YAML frontmatter (id and title fields omitted) followed by body.

func (*Doc) DeleteField

func (d *Doc) DeleteField(id string) error

DeleteField removes a field everywhere it is referenced. The id field stays.

func (*Doc) DeleteRow

func (d *Doc) DeleteRow(rowID string)

DeleteRow removes a row.

func (*Doc) DuplicateRow

func (d *Doc) DuplicateRow(rowID string) (Row, bool)

DuplicateRow copies a row's cells into a new row placed after it.

func (*Doc) EnsureSelectOption

func (d *Doc) EnsureSelectOption(fieldID, rawValue string) bool

EnsureSelectOption mints an option for a select field when the value is new. Option values may not contain commas (the multiSelect separator). Returns true when the schema changed.

func (*Doc) FieldByID

func (d *Doc) FieldByID(id string) *Field

FieldByID finds a field.

func (*Doc) HiddenColumns

func (d *Doc) HiddenColumns(viewID string) []Field

HiddenColumns lists the fields a table view hides (never the id field).

func (*Doc) MoveColumn

func (d *Doc) MoveColumn(viewID, fieldID, direction string) error

MoveColumn shifts a column one visible step left or right in a table view; a no-op at the edges.

func (*Doc) RecordTitle

func (d *Doc) RecordTitle(row Row) string

RecordTitle is a row's display title: the title field's value or Untitled.

func (*Doc) RemoveSelectOption

func (d *Doc) RemoveSelectOption(fieldID, value string) error

RemoveSelectOption drops an option from a select field.

func (*Doc) RemoveView

func (d *Doc) RemoveView(viewID string) error

RemoveView deletes a view, keeping at least one.

func (*Doc) RenameField

func (d *Doc) RenameField(id, name string) error

RenameField changes the CSV header of a field.

func (*Doc) RenameView

func (d *Doc) RenameView(viewID, name string) error

RenameView changes a view's name.

func (*Doc) Resync

func (d *Doc) Resync() error

Resync refreshes the typed fields and views from the sidecar object.

func (*Doc) RetypeField

func (d *Doc) RetypeField(id, typ string) error

RetypeField changes a field's type, keeping the raw cell values.

func (*Doc) RowByID

func (d *Doc) RowByID(id string) *Row

RowByID finds a row.

func (*Doc) SetActiveView

func (d *Doc) SetActiveView(viewID string) error

SetActiveView records which view opens by default.

func (*Doc) SetBoardColumnOrder

func (d *Doc) SetBoardColumnOrder(viewID string, order []string) error

SetBoardColumnOrder stores the column order of a board view.

func (*Doc) SetCardFields

func (d *Doc) SetCardFields(viewID string, fieldIDs []string) error

SetCardFields chooses which fields a board card shows.

func (*Doc) SetCell

func (d *Doc) SetCell(rowID, fieldID, value string)

SetCell writes one cell.

func (*Doc) SetFieldHidden

func (d *Doc) SetFieldHidden(viewID, fieldID string, hidden bool) error

SetFieldHidden hides or shows a column in a table view.

func (*Doc) SetFieldOptionsSource

func (d *Doc) SetFieldOptionsSource(fieldID string, source *OptionsSource) error

SetFieldOptionsSource points a select field at notes for its options, or back to the manual list when source is nil.

func (*Doc) SetGroupBy

func (d *Doc) SetGroupBy(viewID, fieldID string) error

SetGroupBy points a board view at a select field.

func (*Doc) SetOptionColor

func (d *Doc) SetOptionColor(fieldID, value, color string) error

SetOptionColor records a palette token for a select option.

func (*Doc) SetViewFilters

func (d *Doc) SetViewFilters(viewID string, filters []FilterRule, conjunction string) error

SetViewFilters replaces a view's filters and how they combine.

func (*Doc) SetViewSorts

func (d *Doc) SetViewSorts(viewID string, sorts []SortRule) error

SetViewSorts replaces a view's sort rules.

func (*Doc) TitleFieldID

func (d *Doc) TitleFieldID() string

TitleFieldID is the first non-id field: the record title column.

func (*Doc) ViewByID

func (d *Doc) ViewByID(id string) *View

ViewByID finds a typed view.

func (*Doc) VisibleColumns

func (d *Doc) VisibleColumns(viewID string) []Field

VisibleColumns lists a table view's fields in display order, minus the hidden ones and the id column.

type Field

type Field struct {
	ID      string
	Name    string
	Type    string
	Options []SelectOption
	Hidden  bool
	// OptionsSource, when set, discovers select options from notes instead
	// of the explicit list: every note, a folder's notes, or a tag's.
	OptionsSource *OptionsSource
	// contains filtered or unexported fields
}

Field is one typed column.

func InferFields

func InferFields(headers []string, sampleRows [][]string) (idFieldID string, fields []Field)

InferFields builds fields (and picks the id field) for a CSV that has no sidecar yet. A usable `id` column (all unique, non-empty) becomes the id field; otherwise a leading hidden `id` field is synthesized.

type FileMover

type FileMover interface {
	RenameFile(oldRel, newRel string) error
}

FileMover is implemented by backends that can rename a file in place, which loose-CSV renames and conversions need.

type FileOps

type FileOps interface {
	ReadFileTextOrNull(rel string) (*string, error)
	WriteFile(rel, text string) error
	CreateFolder(folder vault.NoteFolder, subpath string) error
	RenameFolder(folder vault.NoteFolder, oldSubpath, newSubpath string) (string, error)
	// ListFolders must include `.base` folders.
	ListFolders() ([]vault.FolderEntry, error)
	VaultLayout() (Layout, error)
}

FileOps is the generic vault-file IO a transport provides. ReadFileTextOrNull must return nil for an ABSENT file and an error for anything else: nil is read as "no schema yet" and a schema is then inferred and written.

type FilterRule

type FilterRule struct {
	FieldID string
	Op      string
	Value   string
}

FilterRule is one view filter.

type Layout

type Layout struct {
	PrimaryNotesAtRoot bool
	SystemFolderPaths  map[string]string
}

Layout is the vault layout facts path composition depends on.

type Object

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

Object is a JSON object that remembers key order. schema.json is user-visible and user-editable, and the app re-serializes it as parsed, so a round trip through here must keep every key where it was, known or not.

func DefaultView

func DefaultView(fields []Field) (*Object, string)

DefaultView is a single Table view (id hidden) over the fields in order.

func NewObject

func NewObject() *Object

NewObject makes an empty ordered object.

func ParseObject

func ParseObject(text string) (*Object, error)

ParseObject decodes JSON text into an ordered object.

func (*Object) Array

func (o *Object) Array(key string) []any

Array reads an array value or nil.

func (*Object) Bool

func (o *Object) Bool(key string) bool

Bool reads a boolean value or false.

func (*Object) Clone

func (o *Object) Clone() *Object

Clone copies the object deeply.

func (*Object) Delete

func (o *Object) Delete(key string)

Delete removes a key.

func (*Object) Get

func (o *Object) Get(key string) (any, bool)

Get reads a value.

func (*Object) Keys

func (o *Object) Keys() []string

Keys lists the keys in order.

func (*Object) MarshalJSON

func (o *Object) MarshalJSON() ([]byte, error)

MarshalJSON encodes the object in key order without HTML escaping, the way JSON.stringify does.

func (*Object) Object

func (o *Object) Object(key string) *Object

Object reads a nested object or nil.

func (*Object) Set

func (o *Object) Set(key string, value any)

Set writes a value, appending a new key at the end.

func (*Object) String

func (o *Object) String(key string) string

String reads a string value or "".

func (*Object) UnmarshalJSON

func (o *Object) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes an object keeping key order; numbers stay as json.Number so their spelling survives a round trip.

type Ops

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

Ops composes database operations over FileOps.

func NewOps

func NewOps(io FileOps) *Ops

NewOps binds the composition to a transport.

func (*Ops) ConvertToFolder

func (o *Ops) ConvertToFolder(csvPath string) (string, error)

ConvertToFolder turns a loose CSV into a `<Name>.base` folder database, which is what record pages need. It returns the new data.csv path.

func (*Ops) CreateDatabase

func (o *Ops) CreateDatabase(folder vault.NoteFolder, subpath, title string) (*Doc, error)

CreateDatabase creates an empty database with an id and a Name field.

func (*Ops) CreateRecordPage

func (o *Ops) CreateRecordPage(csvPath, title, body string) (string, error)

CreateRecordPage writes a record page note inside the database folder and returns its vault-relative path.

func (*Ops) ListDatabases

func (o *Ops) ListDatabases() ([]Summary, error)

ListDatabases finds every `.base` folder.

func (*Ops) OpenDatabase

func (o *Ops) OpenDatabase(csvPath string) (*Doc, error)

OpenDatabase hydrates a database. A CSV without a sidecar is adopted: its schema is inferred and materialized, and its rows re-written with ids.

func (*Ops) RenameDatabase

func (o *Ops) RenameDatabase(csvPath, newTitle string) (string, error)

RenameDatabase renames the `.base` folder and returns the new csv path.

func (*Ops) WriteRows

func (o *Ops) WriteRows(csvPath string, rows []Row) (*Doc, error)

WriteRows persists rows through the cheaper rows-only route.

func (*Ops) WriteSchema

func (o *Ops) WriteSchema(csvPath string, doc *Doc) (*Doc, error)

WriteSchema persists a sidecar and rows together, for edits that mint options or change the pages map.

type OptionsSource

type OptionsSource struct {
	Kind string // notes, folder, tag
	Path string // folder: vault-relative directory
	Tag  string // tag: without the #
}

OptionsSource names where a select field's options come from.

func (*OptionsSource) Describe

func (s *OptionsSource) Describe() string

Describe is the source's display text.

type Row

type Row struct {
	ID    string
	Cells map[string]string
}

Row is one record; cells are raw CSV strings keyed by field id.

func FilterRows

func FilterRows(rows []Row, filters []FilterRule, doc *Doc, conjunction string) []Row

FilterRows applies a view's filters; `or` keeps rows matching any rule.

func ParseRows

func ParseRows(csvText string, fields []Field, idFieldID string) []Row

ParseRows hydrates rows given the known fields. Columns match fields by header NAME, so external column reordering is harmless; rows without an id get one.

func SortRows

func SortRows(rows []Row, sorts []SortRule, doc *Doc) []Row

SortRows applies a view's sorts, stable.

type SelectOption

type SelectOption struct {
	ID    string
	Value string
	Label string
	Color string
}

SelectOption is one pickable value of a select field.

type SortRule

type SortRule struct {
	FieldID   string
	Direction string
}

SortRule is one view sort.

type Summary

type Summary struct {
	Path  string `json:"path"`
	Title string `json:"title"`
}

Summary is a listing entry.

type View

type View struct {
	ID                string
	Name              string
	Type              string
	Filters           []FilterRule
	FilterConjunction string
	Sorts             []SortRule
	ColumnOrder       []string
	HiddenFieldIDs    []string
	GroupByFieldID    string
	BoardColumnOrder  []string
	// CardFieldIDs lists the fields a board card shows under its title;
	// empty means every field.
	CardFieldIDs []string
}

View is a saved table or board configuration.

Jump to

Keyboard shortcuts

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