Documentation
¶
Index ¶
- Constants
- Variables
- func AppendKey(b []byte, v *Value) []byte
- func Arrives(src Source) bool
- func CacheCost() int
- func CacheLimit() int
- func Compare(a, b *Value, collation string) int
- func CompareLevels(a, b []*Value, levels []Level) int
- func Equal(a, b *Value) bool
- func FilterKey(f *Filter) string
- func Key(v *Value) string
- func Match(id *Value, rec Subject, f *Filter) bool
- func MemberIndex(name string) (int, bool)
- func ParseDelimited(text string, opts Delimited) (*ListSource, []Complaint, error)
- func Rank(v *Value) int
- func Segment(v *Value) string
- func SetCacheLimit(n int)
- func SortKey(levels []SortLevel) string
- func TellOnArrival(src Source, tell func()) bool
- type AmendedSource
- func (a *AmendedSource) Add(key *Value, fields Record)
- func (a *AmendedSource) Alter(key *Value, members Record)
- func (a *AmendedSource) Amended() bool
- func (a *AmendedSource) Amendment(key *Value) (Amendment, bool)
- func (a *AmendedSource) Amendments() []Amendment
- func (a *AmendedSource) Delete(key *Value, known Record)
- func (a *AmendedSource) Forget(key *Value)
- func (a *AmendedSource) Open(descriptor *DataSetDescriptor) (DataSet, error)
- func (a *AmendedSource) Replace(key *Value, fields Record)
- func (a *AmendedSource) Stale(key *Value)
- func (a *AmendedSource) TreeFields() TreeFields
- func (a *AmendedSource) TreeHint() TreeHint
- func (a *AmendedSource) WhenArrived(tell func())
- type Amendment
- type Arriving
- type Branch
- type CachedSource
- func (c *CachedSource) Covers(descriptor *DataSetDescriptor) []Extent
- func (c *CachedSource) Open(descriptor *DataSetDescriptor) (DataSet, error)
- func (c *CachedSource) Stale(descriptor *DataSetDescriptor, n Notice)
- func (c *CachedSource) TreeFields() TreeFields
- func (c *CachedSource) TreeHint() TreeHint
- func (c *CachedSource) WhenArrived(tell func())
- type Census
- type Censusing
- type Change
- type ColumnKind
- type Complaint
- type Complete
- type ComposedSource
- type Counting
- type Criterion
- type DataSet
- type DataSetDescriptor
- type Delimited
- type Extent
- type Field
- type Filter
- type Group
- type HintSaid
- type Hinting
- type Identity
- type Include
- type Kind
- type Level
- type ListSource
- func CensusSource(t Census) *ListSource
- func NewListSource(rows []Row) *ListSource
- func NewPSLSource(n *pawscript.PSLNode, reading Reading) *ListSource
- func NewPSLSourceExcept(n *pawscript.PSLNode, reading Reading, skip ...string) *ListSource
- func ParsePSLSource(text string, reading Reading) (*ListSource, error)
- type Mark
- type Marks
- func (m *Marks) Clear()
- func (m *Marks) Close(chain ...string)
- func (m *Marks) Flat(chain ...string) bool
- func (m *Marks) Held() int
- func (m *Marks) Mark(chain ...string) Mark
- func (m *Marks) Open(chain ...string)
- func (m *Marks) OpenAll(chain ...string)
- func (m *Marks) Set(state Mark, chain ...string)
- func (m *Marks) Showing(tell func(chain []string, state Mark))
- func (m *Marks) Shows(chain ...string) bool
- type Node
- type NodeType
- type NodeTypes
- type Notice
- type Placing
- type Reading
- type Record
- type RecordCount
- type Roles
- type Row
- type Scope
- type Sink
- type SortLevel
- type Source
- type Standing
- func (st Standing) Check() error
- func (st Standing) ChildrenByLocation(field string) Criterion
- func (st Standing) DescendantsByLocation(field string) Criterion
- func (st Standing) Join(container, name string) string
- func (st Standing) PathOf(above string, key *Value, r Record) string
- func (st Standing) Paths() bool
- func (st Standing) Under(path string) string
- type Stop
- type Subject
- type Totals
- type TreeFielded
- type TreeFields
- type TreeHint
- type TreeOptions
- type TreeSource
- func (t *TreeSource) Collapse(chain ...string)
- func (t *TreeSource) CollapseAll()
- func (t *TreeSource) Expand(chain ...string)
- func (t *TreeSource) ExpandAll(chain ...string)
- func (t *TreeSource) MarkedByPath(kind string) bool
- func (t *TreeSource) Marks() *Marks
- func (t *TreeSource) Open(descriptor *DataSetDescriptor) (DataSet, error)
- func (t *TreeSource) SortBy(byKind map[string][]SortLevel)
- func (t *TreeSource) Stale()
- func (t *TreeSource) TreeFields() TreeFields
- func (t *TreeSource) WhenArrived(tell func())
- type Value
Constants ¶
const ( CensusValue = "value" // the distinct value, which is also the record's identity CensusCount = "count" // how many records hold it CensusExact = "exact" // whether that count is the whole figure or a floor )
The fields a census record carries. They are bare rather than dotted because a census MAKES its records, and a dot is how a name says it is a member of a record somebody else wrote.
const ( CollateExact = "exact" // codepoint order, rune by rune CollateFold = "fold" // ASCII case folded, then exact CollateNatural = "natural" // digit runs as numbers, then fold )
The collations text may be compared under. A symbol and a run of bytes take none: a symbol is a name, and bytes are not text.
const ( RankUndefined = iota RankNil RankFalse RankTrue RankNumber // int and float share one rank and interleave by value RankSymbol RankString RankBytes RankUnordered // no order of its own; the sort's last level settles it )
A value's rank, which its kind decides before anything in it is read.
const ( KeyField = "key" ValueField = "value" )
The two names the Whole reading gives a record's own key and value.
These are fields, and only fields. A record read this way carries `key` because the document gave it one and somebody may want to sort or show it -- not because this end works by it. What identifies the record travels beside the bag, and a document is free to hold a member called `key` of its own without the two ever meaning the same thing.
const ( OpAnd = "and" OpOr = "or" OpNot = "not" OpEq = "eq" OpNe = "ne" OpLt = "lt" OpLe = "le" OpGt = "gt" OpGe = "ge" OpIn = "in" OpContains = "contains" OpStarts = "starts" OpEnds = "ends" // OpHas and OpLacks ask whether a record carries a field at all, and take // no value. Every other operator compares one, and a field holding // something with no order of its own -- a nested list -- cannot be // compared, so presence needs an operator that does not try. OpHas = "has" OpLacks = "lacks" // OpID matches a record's identity against a set of them, the way `in` // matches a field against a set of values. It names no field, because an // identity is not one: it travels beside a record's fields rather than // among them, and a field called `key` is a field like any other. OpID = "id" )
The operators a filter is built from.
const MostRevisits = 3
The most laps anybody may ask for. The reason to allow any is to make a cycle VISIBLE, and nobody has ever needed a fourth to see one.
Variables ¶
var TreeFieldsDefault = TreeFields{
Depth: "depth",
Path: "path",
Expandable: "expandable",
State: "state",
Kind: "kind",
Chain: "chain",
}
TreeFieldsDefault is what a tree writes where the caller says nothing.
Functions ¶
func AppendKey ¶
AppendKey appends a value's Key to b, for a caller building a key out of more than one thing. A table keyed by a sequence and an identity wants one buffer and one string, not a key per part and a join afterwards.
func Arrives ¶
Arrives reports whether a source may answer AFTER its read returns -- itself, or anything it wraps.
**It is not the same question as "does it implement Arriving", and that is the whole reason it exists.** A wrapper hands the notice on, so it implements the interface whatever its child does: a cache over a list of records in hand is `Arriving` and will never fire, because there is nothing under it to fire.
Asserting the interface to decide whether to WAIT is therefore wrong, and wrong in the expensive direction. A tree that concluded its levels might answer late walked on a goroutine of its own and returned no rows, expecting a notice to bring the reader back -- and no notice ever came, the records having been there all along. The tree read empty forever. That is what this is for; see `answersLater`.
A wrapper is asked about its child. Anything else is asked whether it can arrive at all, which for a source that is not one of these wrappers is the same question.
func CacheLimit ¶
func CacheLimit() int
CacheLimit is how much the process holds, and SetCacheLimit changes it, evicting down to the new figure at once. It is one figure for every CachedSource there is.
func Compare ¶
Compare orders two values: -1, 0 or 1. The collation applies to the string rank alone and is CollateExact when empty.
Two values of different ranks are decided by the ranks. Two of the same rank are decided by what is in them, except the ranks that hold one value each (undefined, nil, false, true) and the unordered rank, which compare equal and leave the answer to the sort's last level.
func CompareLevels ¶
CompareLevels walks the levels in order and answers on the first that separates the two runs, so each level settles only what the ones above it left equal. A run shorter than the levels stops where it ends.
The caller appends the record's identity as a final level: two records equal on every level a sort names must still have an order, or "the record after this point" names more than one place.
func Equal ¶
Equal reports whether two values are the same value.
Three things it decides, and each is written down in 0_identity_test.go so that changing one is a deliberate act:
- Text and bytes of the same content are NOT the same value. They are different kinds -- one is characters and one is not -- and they do not even sort together.
- An integer and a float of the same magnitude are not the same value either. 3 and 3.0 are different numbers here, and a boundary that changed type between two holders of the same sequence would be comparing different things.
- Floats compare by their bits and not by ==, which makes NaN equal to itself and 0.0 different from -0.0. That is not a preference: a key must be reflexive, or a record whose identity does not equal itself is filed and never found again, and == on NaN gives exactly that.
func Key ¶
Key is a value's canonical form: two values have the same Key exactly when Equal says they are the same value.
Self-delimiting, so keys can be concatenated -- which is what a table keyed by more than one thing does, and what a list of them does inside one key.
func Match ¶
Match reports whether a record passes a filter. A nil filter passes everything, which is what an unfiltered sequence is.
The identity comes in beside the record rather than as a field of it, because that is what it is: `id` asks about the identity, and every other operator asks about a field. A record whose fields happen to include one called `key` is answering an ordinary question about an ordinary field. Pass nil for id where there is none, and `id` then matches nothing.
func MemberIndex ¶
MemberIndex reads a field name as an ordered member's index.
An ordered member is named by its position written out -- `0`, `1`, `2`, or `.0`, `.1`, `.2` where the source marks its members with a leading dot -- and only in that spelling: no sign, and no leading zeros but `0` itself. So `007` is a NAME that happens to be digits rather than the member at seven, which is the same distinction everything else here makes between a name and a number.
**This is the rule, and a source counting its members has to count by it.** Totals that said a record had no ordered members while naming one `.0` would have this answer "index 0 is not there" about a member that is, which is the one way a total can be worse than no total at all. Tally counts by this rule and is what a source should use.
func ParseDelimited ¶
func ParseDelimited(text string, opts Delimited) (*ListSource, []Complaint, error)
ParseDelimited reads a delimited file as records.
The error is for text that is not rows at all. Everything else is a complaint, and a file that produced complaints is still a source.
func Rank ¶
Rank is where a value sits before its contents matter. A value that is not there at all is undefined, which is the bottom of the order.
The kind decides it outright. Nothing is read out of the value and nothing is spelled: which rank a value has is a fact about what it IS.
func Segment ¶
Segment is a value as a piece of a path: the characters themselves, and not the readable rendering.
Value.String quotes text, which is right for standing and wrong here -- a path segment is what the field HOLDS. Nothing is parsed back out of this: it is compared, and joined, and used to key a mark.
func SetCacheLimit ¶
func SetCacheLimit(n int)
func SortKey ¶
SortKey and FilterKey name the other two halves of a prepared sequence, for the same reason and on the same terms. A sequence is a source, a sort and a filter, and whatever holds one per sequence has to be able to say when two are the same sequence.
func TellOnArrival ¶
TellOnArrival asks a source to say when records land, and reports whether it can.
False is not a failure: it is a source that answers `Read` before it returns, which needs no telling and is the ordinary case. A reader that gets false has nothing to arrange and reads as it always did.
Types ¶
type AmendedSource ¶
type AmendedSource struct {
// What it says its records ARE, where somebody has said; see treehint.go.
HintSaid
// contains filtered or unexported fields
}
An AmendedSource holds replacements and deletions against a child's records.
func NewAmendedSource ¶
func NewAmendedSource(child Source) *AmendedSource
NewAmendedSource amends the records of a child source. The child is any kind -- records here, records an application's, or another amended source.
func (*AmendedSource) Add ¶
func (a *AmendedSource) Add(key *Value, fields Record)
Add says this source holds a record of its own under this key.
It is not a statement about anything the child holds: the key is the author's to choose, and keeping it clear of the child's is the author's to do. Where it turns out not to be clear, the child's record is the one that stands and this one is dropped for good -- the opposite of Replace, which displaces whatever the child has.
func (*AmendedSource) Alter ¶
func (a *AmendedSource) Alter(key *Value, members Record)
Alter says SOME of a record changes and the rest is the child's.
The one amendment that is not a record entire, and it is what a cell edit is: a reader changed one member of one row and said nothing whatever about the others. Stating it as a Replace would mean holding the whole record to state it with, and a reader that has drawn five columns of a forty-member record has not got one.
Three things follow from it being partial, and they are the reason it is worth having rather than a convenience:
- **It cannot move the record.** The child applies the filter and the sort and places the record; this touches what the record HOLDS afterwards. So a row stays where it was until something asks the question again -- which is what a reader editing a cell wants, the row not leaping away under the cursor.
- **It cannot change how many there are.** The child counted it and still does.
- **It means nothing for a key the child does not send.** There is no record to alter, so nothing goes out. That is the opposite of Replace, which stands on its own, and it is why an alteration is not a way to add anything.
**Altering accumulates.** Two edits to two columns of one row are two calls, and the second must not lose the first -- so the members are merged into whatever is held: into an alteration, into a replacement's or an addition's own fields (both being records entire, a member of one is well defined), and into nothing at all for a key that was deleted, the record being gone.
func (*AmendedSource) Amended ¶
func (a *AmendedSource) Amended() bool
Amended reports whether anything is held at all, for a caller asking whether there is anything to save.
func (*AmendedSource) Amendment ¶
func (a *AmendedSource) Amendment(key *Value) (Amendment, bool)
Amendment is what is held against ONE key, and false where nothing is.
The per-key form of Amendments, for a reader that has a record in hand and wants to know whether this source has anything to say about it. A caller with a flattening taken before an amendment was made is reading a snapshot that predates it, and this is how the snapshot is corrected without asking the whole sequence again -- the amendment being the authority over anything older than itself.
func (*AmendedSource) Amendments ¶
func (a *AmendedSource) Amendments() []Amendment
Amendments is every statement this source holds.
**It is here because an amendment is meant to outlive the session that made it.** A reader edits a cell, the edit is held here, and somebody eventually has to write it to a file or a database -- which is impossible if the only way to see one is to read the records back and diff them against a child that has meanwhile moved on. So what is held can be asked for.
Ordered by key, which is not the order they were made in and is deliberately not: the map holds one statement per key, so the making order has already been collapsed, and reporting some order would suggest a history that is not kept. A stable one is what a caller writing a file wants.
func (*AmendedSource) Delete ¶
func (a *AmendedSource) Delete(key *Value, known Record)
Delete says a record is gone.
Known is what was last seen of it, and may be nil. With it, the scope that record would have fallen in is known before the child is asked; without it, the shortfall is discovered afterwards and costs a second question -- which is also where the fields to remember are learned.
func (*AmendedSource) Forget ¶
func (a *AmendedSource) Forget(key *Value)
Forget drops an amendment, leaving the child's own record to stand.
func (*AmendedSource) Open ¶
func (a *AmendedSource) Open(descriptor *DataSetDescriptor) (DataSet, error)
Open states a sequence, and opens the same one on the child.
func (*AmendedSource) Replace ¶
func (a *AmendedSource) Replace(key *Value, fields Record)
Replace says a record now carries these fields, whatever the child holds.
These are the record entire, not a correction to some of it: what goes out for this key is exactly what is stated here, and it goes out as a whole record.
func (*AmendedSource) Stale ¶
func (a *AmendedSource) Stale(key *Value)
Stale says the child's own record under this key may have changed, so what was shadowed of it is no longer to be trusted.
This source holds no runs and no values, so it needs no extent and no reason: what it keeps of the child is one record per amended key, and either that is still right or it is not. Told, never decided -- the same rule as everywhere, because a shadow is knowledge like any other and goes stale like any other.
A count that was exact because of a shadow falls back to a floor, and a deletion that had a placement goes back to being ruled out of no scope.
func (*AmendedSource) TreeFields ¶
func (a *AmendedSource) TreeFields() TreeFields
func (*AmendedSource) TreeHint ¶
func (a *AmendedSource) TreeHint() TreeHint
TreeHint: an amendment's own where one was said, and otherwise the child's.
**Amending a record does not reshape it.** A replacement is a record in the same world as the ones around it -- that is what makes it a replacement rather than a different source -- so a child that says its records are a hierarchy is describing the amended ones too.
Its own wins because it is the more specific saying: whoever assembled this layer and described it knows what the layer is, and a bundle is exactly that case.
func (*AmendedSource) WhenArrived ¶
func (a *AmendedSource) WhenArrived(tell func())
WhenArrived passes the notice on to the source this amends. The amendments are here and they do not arrive; the records do.
type Amendment ¶
type Amendment struct {
// Key is the record this is about.
Key *Value
// How is which of the four things has been said about it, in the same words a
// source uses to ANNOUNCE one: Added, Removed, Replaced, Altered.
//
// **They are the same four facts, so they are the same four words.** A
// `Change` is one of them told to a reader; an amendment is one of them held
// against a child. Giving the held version four words of its own would mean
// two vocabularies for one idea, and a reader turning `Delete` into "removed"
// by hand.
How Change
// Fields is the record entire for Replaced and Added, the members that change
// for Altered, and nil for Removed -- the record being gone, there is nothing
// of it to state.
Fields Record
// Clashed marks an addition whose key turned out to be the child's after all.
// The child's record stands and this one no longer goes out, so it is here to
// be seen and dealt with rather than written out as though it were in force.
Clashed bool
}
An Amendment is one statement this source holds, as a caller reads it back.
A copy, so that amending afterwards does not change one already handed out.
type Arriving ¶
type Arriving interface {
// WhenArrived adds something to be told once an answer has landed. It ADDS,
// because several readers may share one source.
//
// It is called on whatever thread the records arrived on. A reader that
// cannot be touched from there is the one that knows so, and arranges
// accordingly.
WhenArrived(tell func())
}
An Arriving source can say when records have landed.
Optional, as every one of these is: a source that does not implement it answers at once, and `TellOnArrival` is what a reader asks rather than asserting.
type Branch ¶
type Branch struct {
// Kind is the node type the children are.
Kind string
// When is a predicate on the PARENT. Nil is always, which is what makes the
// unconditional case free -- Match passes a nil filter.
//
// It is a `*Filter` because that is what this library already says a
// predicate with, down to the collation. `ends name ".zip"` needs nothing
// new, and the alternative -- a Go function -- could not be written down in
// a bundle later.
//
// **It tests the row's own values and not a field an author added.** The
// override field exists for a row announcing something about itself, and
// wanting the data to carry the view's vocabulary is what this avoids: a
// filesystem listing has an extension and has never heard of a node type.
When *Filter
}
A Branch is one kind of thing that hangs off a row, and when it does.
type CachedSource ¶
type CachedSource struct {
// contains filtered or unexported fields
}
A CachedSource answers out of the process's cache wherever it can, and asks the source it wraps wherever it cannot.
func NewCachedSource ¶
func NewCachedSource(child Source) *CachedSource
NewCachedSource wraps a source.
Wrap once and keep the wrapper: it is the name under which everything it learns is filed, so a second wrapper over the same source starts knowing nothing.
func (*CachedSource) Covers ¶
func (c *CachedSource) Covers(descriptor *DataSetDescriptor) []Extent
Covers is what this wrapper currently depends on for one sequence: the stretches of it being held.
**The stated coverage is a superset of what is actually depended on**, which is the rule the whole arrangement stands on. Stating more is safe -- a staleness reported for something already let go of is ignored. Stating less is a missed invalidation, which is silent and permanent. These are taken from what is held, so they are exactly it, which satisfies the rule with nothing to spare and nothing to get wrong.
**In no particular order.** They are stretches of one sequence, but which stretch comes before which is a question about the ORDER, and comparing two identities needs the records they name. Whoever asked holds that order and can sort them; this cannot.
func (*CachedSource) Open ¶
func (c *CachedSource) Open(descriptor *DataSetDescriptor) (DataSet, error)
Open states a sequence, and opens the same one on the child.
The child is opened whether or not anything is ever asked of it. Opening is where a source REFUSES a sequence it cannot produce exactly, and a refusal that only arrived once the cache happened to miss would be a refusal that depended on what was in memory.
func (*CachedSource) Stale ¶
func (c *CachedSource) Stale(descriptor *DataSetDescriptor, n Notice)
Stale tells this wrapper that something it may be holding is no longer true.
The descriptor names the sequence the extent is stated in, and a nil one says the notice is about records and not about anyone's order -- which is what a record known to the source but placed in no live sequence needs, there being no stretch to name it in.
Nothing is fetched. What is no longer true is let go of.
func (*CachedSource) TreeFields ¶
func (c *CachedSource) TreeFields() TreeFields
func (*CachedSource) TreeHint ¶
func (c *CachedSource) TreeHint() TreeHint
TreeHint: a cache holds the same records under the same keys, so whatever the child says about their shape is true of what comes out.
func (*CachedSource) WhenArrived ¶
func (c *CachedSource) WhenArrived(tell func())
WhenArrived passes the notice on to whatever this cache wraps.
A cache does not fire one of its own: what it holds it holds, and an answer landing at the far end is the CHILD's news. Telling the cache its runs are stale is a different saying with a different name -- see invalidate.go.
type Census ¶
type Census struct {
// Groups, in the order of their values -- which is an order and not an
// arrangement, so that two censuses of one sequence are the same answer and
// a test can say what it expects. A caller wanting them by size sorts them,
// or reads them through CensusSource and says `sort={ count desc }`.
Groups []Group
// Total is how many distinct values there are: Exactly(n) meaning these n
// and no others, AtLeast(n) meaning at least these.
//
// It is the second of the three claims, and it is why this is a struct
// rather than a slice. A slice of exact counts cannot say "and there may be
// more groups I have not seen", which is precisely what a source that has
// read part of a sequence has to be able to say.
Total RecordCount
}
A Census is the answer: the groups, and whether they are all of them.
func CensusOf ¶
CensusOf partitions a data set's sequence by a field, and says it cannot for a data set that is not Censusing.
The error is the point. CountOf answers Unknown for a set that cannot count, because a floor of nought is a true statement about every sequence; there is no such harmless answer here, an empty census claiming there are no groups at all. So this refuses instead, and a caller falls back to whatever it had.
func (Census) CountOfGroup ¶
func (t Census) CountOfGroup(v *Value) RecordCount
CountOfGroup is the count for one value, and the honest answer for a value this census has not got: nought exactly where the census is complete, because then there is nothing left for it to be, and Unknown where it is not.
This is the question a tree actually asks -- has this row any children, and how many -- so it is worth answering here rather than at every caller, where the difference between "no children" and "I did not see" would get lost.
type Censusing ¶
A Censusing data set can partition its sequence by a field and count each part.
Optional, and deliberately so, on the model of Counting: the least a data set can do stays one method, and one that cannot take one simply is not one of these. Ask with CensusOf.
**A data set that cannot take one says so rather than walking.** Over records in hand the work is a pass over records already here, which is exact and cheap. Over a source that must be ASKED and cannot, walking the sequence to count it is precisely what the caller was avoiding -- and a census that quietly became a full scan would be fast in testing and ruinous in use.
type Change ¶
type Change int
A Change is why what is held is no longer true.
const ( // Added: a record appeared. It names no record anyone holds, so the extent // names the two it fell BETWEEN -- First the one it falls after, Last the // one it falls before -- either of which may be absent where it fell past // an end. Added Change = iota // Removed: a record has left the sequence altogether. Removed // Replaced: a record is still there and everything about it may be // different, which is the same as every field having changed. Replaced // Altered: the named fields may have changed. MAY, not did -- a source that // cannot tell exactly which is welcome to name more than changed, or to say // Replaced and be done. Over-stating costs a refill; under-stating is a // wrong answer nobody finds out about. Altered )
type ColumnKind ¶
type ColumnKind int
A ColumnKind is what a declared column holds, whatever its cells look like. It is the column that says so, so quoting in a declared column is transport and carries no meaning of its own.
const ( // Inferred is the cell's own business: see Delimited.Infer. Inferred ColumnKind = iota AsString AsSymbol AsNumber // AsBytes reads the wire's escapes whatever Escapes says, because \xNN is // the only way a cell can spell a byte. AsBytes )
type Complaint ¶
type Complaint struct {
Row int // the row it was in, counting data rows from zero
Column string // the column, as the rows name it
Cell string // what was there
Reason string
}
A Complaint is one thing that was wrong with one cell or one row.
It is a report and not a refusal: the cell is left undefined, the row is kept, and the load carries on. One bad cell in a long file costs that cell.
type Complete ¶
type Complete struct {
Watermark *Value
Stop Stop
// Total is how many records the whole SEQUENCE has, where the source knows
// and volunteers it.
//
// Optional. A source that cannot count cheaply says nothing, which is
// Unknown; one that can says it on an answer it was sending anyway rather
// than waiting to be asked. It is a fact about the ORDER, which is why it
// rides here beside the watermark and the ending word -- and about the
// sequence rather than this scope of it, how many came back being something
// whoever asked can count.
Total RecordCount
// First is where in the sequence the answer actually started: the position
// of the first record it carried, counted in the sequence's own order
// however the scope walked it.
//
// It is the calibration, and it is nearly free wherever it is possible at
// all -- a source that resolved a start knows what it resolved. A reader
// that asked After some record it holds learns where that record stands
// without a question of its own; a reader that asked From a position learns
// whether it got there. Beside Total, the two say how long the sequence is
// and where in it this answer sits, which between them are a scroll thumb.
//
// **Unknown is an answer and is never inferred.** A source that cannot say
// says nothing, and a reader told nothing stays where it was rather than
// believing a number that was not sent. An answer that carried no records
// has no first record and says Unknown for that reason alone.
//
// **Exactly or Unknown, and never a floor.** A count can honestly be a
// floor -- part of a sequence seen is at least that many -- but a position
// cannot be reckoned the same way: a source either resolved where it began
// or it did not, and "at least the six hundredth" is not something a reader
// can put a thumb on. It shares Total's type for the vocabulary, not for
// the middle value.
First RecordCount
// Error is a refusal, which is an answer: this scope cannot be produced,
// the records are gone, whatever held them is no longer reachable.
// Whoever asked carries on with what it has.
Error string
}
A Complete ends a scope: which of the three ways it ended, and how far the answer is complete.
Watermark says there is nothing between where the scope was asked from and that record that the asker does not now have. StopExhausted carries none, because there is no point past the end to be complete up to.
type ComposedSource ¶
type ComposedSource struct {
// contains filtered or unexported fields
}
A ComposedSource answers out of several sources at once.
func NewComposedSource ¶
func NewComposedSource(includes ...Include) (*ComposedSource, error)
NewComposedSource composes sources under the names their records go out under.
The includes are fixed for the life of the source. A sequence opened over it opens one over each of them, so a set that changed underneath would leave a sequence answering out of children it never opened.
func (*ComposedSource) Includes ¶
func (c *ComposedSource) Includes() []Include
Includes are the sources this one is made of, in the order they were given.
func (*ComposedSource) Open ¶
func (c *ComposedSource) Open(descriptor *DataSetDescriptor) (DataSet, error)
Open states a sequence, and opens it on every include that could hold anything the filter admits.
Each include gets the filter read in its own terms: an identity this source made says which include it came from, so `filter={ id (left/1) }` asks `left` about its own record 1 and never opens `right` at all.
func (*ComposedSource) Stale ¶
func (c *ComposedSource) Stale(key *Value)
Stale says a record this source has placed may no longer be where it was.
It needs no extent and no reason. What this source holds of a record is one note -- where it stood, and where each include stood as it went out -- and either that is still right or it is not. Told, never decided, the same as everywhere else.
**Forgetting a note is safe, which is what makes this cheap.** A note says where this source WAS when it last spoke about a record, so a scope resuming from one it has not got is REFUSED rather than answered wrongly. The whole price of forgetting too much is a refusal, and a refusal is an answer.
It is answered against no sequence, because a record moving is a fact about the record: every order over this source placed it, and every one of them placed it wrongly.
The note of it, and the notes that mention it ¶
Two different things go, and the second is the one that is easy to miss.
The note OF the record is obviously wrong: it says where that record stood and where the includes stood as it went out, and it may have moved.
But a note of ANY OTHER record may name it too. A note's vector holds each include's own cursor -- the last record that include had handed over at that moment -- and this record may be one of them. Resuming from such a note would ask that include to carry on past a record that is no longer where it says, and the include would answer from somewhere else without anyone finding out. So those go as well, and finding them is a walk of a bounded book.
The tuple of where a record STOOD needs no such walk: it is that record's own values and says nothing about anybody else's.
func (*ComposedSource) TreeFields ¶
func (c *ComposedSource) TreeFields() TreeFields
func (*ComposedSource) WhenArrived ¶
func (c *ComposedSource) WhenArrived(tell func())
WhenArrived passes the notice on to every include that can arrive.
**Any one of them is enough**, because a composition's answer is drawn from all of them: a record landing in one changes what the whole says, and a reader that re-reads on it reads the composition rather than the child. So there is no need to know WHICH arrived, and nothing here keeps track.
type Counting ¶
type Counting interface {
RecordCount() RecordCount
}
A Counting data set knows how many records its sequence has.
Optional, and deliberately so: the least a source can do stays one method, and a source that cannot count simply is not one of these. Ask with CountOf, which answers Unknown for anything that is not.
type Criterion ¶
type Criterion struct {
// Of is the question for one node: a DataSetDescriptor naming that node's children.
Of func(of Node) *DataSetDescriptor
// Over and By are how a whole level is counted in one question: the
// sequence every one of these children is drawn from, and the field saying
// which parent each belongs to. Group is the value naming one node's part
// of that census.
//
// **Only a criterion that PARTITIONS can be censused.** A census puts each
// row in exactly one group, so a criterion that puts a row in several
// nodes' answers -- a subtree, where every ancestor claims it -- cannot use
// one, and says so by leaving these out rather than by counting wrongly.
Over *DataSetDescriptor
By string
Group func(of Node) *Value
}
A Criterion says which rows are a node's children -- and, where it can, how a whole LEVEL of that question is answered at once.
The three census parts are here rather than on the node type because they have to agree with Of and with each other, and a place where three things must agree is a place to put them together. A criterion that cannot be censused leaves them out, and every node is then counted on its own.
func ChildrenByKey ¶
ChildrenByKey is `eq <field> <the parent's key>`: an adjacency list, and the commonest hierarchy in a database.
It needs no path, no delimiter and no address field. The parent's identity is compared against the child's parent column, and that is the whole of it.
It partitions -- every row has one value under the field, so it belongs to one parent -- so a census of the source by that field answers every node at once.
func Sorted ¶
Sorted puts a sort on whatever a criterion produces.
**A node type may order its children differently from its parents, and this costs nothing** -- a node type produces a whole DataSetDescriptor, and a DataSetDescriptor is a source, a filter and a sort. Windows in z-order under applications in name order needs nothing added. It is written down because a capability nobody notices gets reinvented. The census parts come through untouched, a count belonging to the filter and not to the order: sorting the same records cannot make there be more or fewer.
type DataSet ¶
type DataSet interface {
// Read asks for one scope of the sequence and says where to put it.
//
// It does not wait for the answer. Records reach the sink as they are
// produced -- immediately, for a source whose records are here; as they
// arrive, for one whose records are somewhere else -- and the sink is told
// what ended it when it ends. The error is for a request that could not be
// started at all, never for one that has not finished.
//
// A scope names its ends by identity, and an identity means something only
// to the source that issued it. So a scope handed here was issued here: a
// source made of several others translates rather than relays.
Read(s *Scope, out Sink) error
// Close lets the data set go, and with it whatever it was holding.
Close()
}
A DataSet is one stated sequence -- this source, this sort, this filter -- prepared once and drawn from until it is let go. It is what a query names, seen from the end that holds the records.
Those three name it, and nothing else does: the fields a query asks for change what a scope carries rather than which records are in the sequence, and the direction belongs to the scope. So two queries naming the same three are reading one data set, and whatever was worked out for either of them -- the ordering, where each record stands -- holds for both.
It does not change. A different sort or a different filter is a different data set, opened alongside this one and taking its place -- which is also what keeps the source in use while the reader moves from one to the other.
type DataSetDescriptor ¶
type DataSetDescriptor struct {
Source string
Fields Record // the fields asked for; empty means whatever the record has
Exclude Record // the fields not wanted, valued the same way
Filter *Filter
Sort []SortLevel
}
A DataSetDescriptor says what sequence a query names: which records, in which order.
Fields and Exclude are what the asker WANTS. What a source carries back may be any superset of that -- sending more than was asked for is always allowed -- but what it CLAIMS to carry must be true, because an answer kept against a later question is answered from what it claims.
func (*DataSetDescriptor) Roles ¶
func (s *DataSetDescriptor) Roles() Roles
Roles groups this descriptor's fields by the part each plays.
The names are in the order they were first met -- sort levels top down, then the filter tree -- and each appears once per group. A stable order matters because this is stated over and over as a sequence is read, and a set that reshuffles itself makes every statement look like a change.
type Delimited ¶
type Delimited struct {
// Delimiter separates cells: one character, and one per file.
Delimiter rune
// Quote begins and ends a quoted cell, and doubled inside one stands for
// itself. A quoted cell may hold the delimiter and may hold newlines.
Quote rune
// Header says the first row names the columns. Without it they are named
// `.0`, `.1` and so on, which is how a position is named everywhere else.
Header bool
// Escapes reads the wire's escape set inside a quoted cell: \\ \" \n \t \r
// \e and \xNN. It is OURS and not a spreadsheet's -- leave it off for
// anything Excel or LibreOffice wrote, or a cell holding a Windows path
// will be read as escapes it never meant.
Escapes bool
// Infer reads a bare cell by the rule the wire reads a bare token by: a
// number where it spells one, a symbol otherwise. Off, every bare cell is
// text, which is what a spreadsheet meant by it.
Infer bool
// Identity says what names a row.
Identity Identity
// Value names the column that becomes the record's `value` rather than a
// member of its own, the way a scalar record carries one.
Value string
// Columns declares what a column holds, by the name the row names it.
Columns map[string]ColumnKind
// Comments begin a line that is not a row: "#", ";", "--", whatever this
// file uses. They are prefixes rather than characters because "--" is two.
//
// A line counts as a comment only where a ROW could have started, so a
// prefix inside a quoted cell -- including one spanning several lines -- is
// part of the cell and not the start of a remark.
Comments []string
}
Delimited is how to read one file.
type Extent ¶
type Extent struct {
First, Last *Value
}
An Extent is a stretch of one sequence that is currently depended on.
Named by its ends the way a scope is -- identities, never positions -- and both ends INCLUSIVE, both being records that are actually held. A scope's ends say where to start and stop walking, which is a different question and is why they are exclusive; an extent says what is covered.
type Field ¶
type Field struct {
// Name is what the member is called, or "" for a member that has no name of
// its own and stands by its position.
Name string
// Value is what is under the name. Nil is undefined, which is a value a
// field can have: a name present with nothing under it.
Value *Value
}
A Field is one member of a record: a name, and what is under it.
type Filter ¶
type Filter struct {
Op string
Field string // predicates: the field being tested
Values []*Value // what it is tested against; more than one only for `in`
Collate string // text predicates: the collation, "" for the default
Children []*Filter // and, or, not
}
A Filter is a tree: a predicate over one field, a test of a record's identity, or an and/or/not over other nodes.
The top of a built filter is an OpAnd, so there is one shape to walk whether the filter held one predicate or twenty.
func (*Filter) String ¶
String is the filter as readable text, in the same shape Record uses: each node as an operator, the field it names and what it is tested against, and a braced block where a node has children. For an error message, a log line, or a test saying what it expected in one line -- never parsed back.
type Group ¶
type Group struct {
// Value is what the field held. Groups are told apart by Key and Equal, so
// 3 and 3.0 are two groups because they are two numbers, and 3 and "3" are
// two groups because one is a number and one is text. Nothing else decides
// this and nothing may -- a census that grouped by a spelling would merge
// values the rest of the library keeps apart.
//
// Nil is `undefined`, which is a group like any other. A field a record has
// not got reads as undefined rather than being left out, so the records
// missing the field are countable and nameable rather than a silence to be
// inferred from an arithmetic that does not add up.
Value *Value
// Count is how many records of the sequence hold it: Exactly where the
// whole sequence was seen, AtLeast where only part of it was.
Count RecordCount
}
A Group is one distinct value of a census field, and how many records of the sequence hold it.
type HintSaid ¶
type HintSaid struct {
// contains filtered or unexported fields
}
A HintSaid is what a source embeds to be able to say what its records are.
It is embedded rather than wrapped, and that is the point. A wrapper forwarding `Open` would have to forward every OPTIONAL interface too -- Counting, Censusing, TreeFielded, and whichever is added next -- and the one it forgot would silently degrade the source it wrapped. Embedding adds a method and changes nothing else.
**The hint is said when the source is assembled, before anybody reads it.** So there is no lock: whoever built the source is the only one holding it at that moment. A source whose shape changes after it has been handed out is not a thing this describes.
func (*HintSaid) SetTreeHint ¶
SetTreeHint says what this source's records are.
type Hinting ¶
type Hinting interface {
TreeHint() TreeHint
}
A Hinting source says what its own records are.
Optional, as every one of these is: a source that says nothing about its shape is answered for by TreeHintOf, which is what a reader asks.
type Identity ¶
type Identity struct {
// contains filtered or unexported fields
}
An Identity says what identifies a row. The zero value is the row's index, which is what an authored file usually wants: these are versioned documents rather than tables somebody inserts into, so a row's position is its name.
func IdentityAt ¶
IdentityAt identifies a row by a column's value, by where the column stands.
func IdentityColumn ¶
IdentityColumn identifies a row by a column's value, named as the row names it: a header, or `.2` where there are no headers.
type Include ¶
An Include is one of the sources a ComposedSource is made of, under the name its records go out prefixed with.
type Kind ¶
type Kind int
Kind is what a value is.
const ( NilValue Kind = iota // nothing, deliberately: a field that has no value BoolValue // true or false NumberValue // an integer or a float; IsInt says which SymbolValue // a name the data uses: an identifier, an enum TextValue // text BytesValue // bytes that are not text ListValue // a record in its own right: a nested thing )
type Level ¶
Level is one level of a sort, as it applies to a pair of values already taken from the two records being ordered.
type ListSource ¶
type ListSource struct {
// What it says its records ARE, where somebody has said. Embedded rather than
// wrapped so that nothing about how the list answers changes; see treehint.go.
HintSaid
// contains filtered or unexported fields
}
ListSource is a body of records held here, presented as a source.
func CensusSource ¶
func CensusSource(t Census) *ListSource
CensusSource presents a census as a body of records: one per group, carrying the value and the count.
**A census is a sequence, so it is a source**, and then it needs no vocabulary of its own for anything a caller will want. A short list of large counts is `sort={ count desc }` with `count=20`; the biggest group is the same with `count=1`; groups over a threshold are a filter; how many distinct values there are is RecordCount. None of that is written here because none of it is new.
A group's identity is the value itself, which is unique by Key -- so nothing is synthesised, and a scope naming where to carry on from names a value the caller was already holding.
func NewListSource ¶
func NewListSource(rows []Row) *ListSource
NewListSource presents rows already in memory as a source. The rows are the source's from here: it does not copy them and it does not change them. What it does with a different set of them is Restate.
func NewPSLSource ¶
func NewPSLSource(n *pawscript.PSLNode, reading Reading) *ListSource
NewPSLSource presents an already-parsed PSL list as a data source: its items as records keyed by index, its keyed members as records keyed by name.
func NewPSLSourceExcept ¶
func NewPSLSourceExcept(n *pawscript.PSLNode, reading Reading, skip ...string) *ListSource
NewPSLSourceExcept is the same, less the keyed members named.
A flat reading takes every keyed member for a record, `_bundle` included, because only the layer above knows which of them are ABOUT the document rather than in it. That layer says so here, and its records are then the document's own with nothing of the format's mixed in.
func ParsePSLSource ¶
func ParsePSLSource(text string, reading Reading) (*ListSource, error)
A PSLSource is a data source backed by one parsed PSL list.
It is read-only and its records do not move, so everything computed from them stays true: an ordering is built once per descriptor and reused for every scope drawn from it. ParsePSLSource reads PSL text and presents it as a data source.
func (*ListSource) Len ¶
func (l *ListSource) Len() int
Len is how many records the source holds, before any filter.
func (*ListSource) Open ¶
func (l *ListSource) Open(descriptor *DataSetDescriptor) (DataSet, error)
Open states a sequence over the records: one filter, one sort.
func (*ListSource) Restate ¶
func (l *ListSource) Restate(rows []Row)
Restate says the list is now these rows.
**It is told, never decided.** Nothing here watches the slice it was handed, compares a length or a generation, or looks again to see: whoever holds the rows says they have changed, and that saying is this. A list nobody tells holds what it holds, which is the same bargain a cache makes.
What it costs is the orderings: every sequence this source had worked out is forgotten, the records that decided where each one stood no longer being the records.
**A sequence already stated goes on answering the one it stated.** An ordering holds the rows it was built over, so a data set opened before this reads the list as it was -- asked once and answered once, which is the rule everywhere else and wants no exception here. A caller who wants the new rows states a new sequence; one holding a CachedSource in front of this tells it `Stale` so the runs it kept go too, and one holding a TreeSource tells that.
type Mark ¶
type Mark int
A Mark is what a node's state can be.
const ( // Closed: this node's children do not show. Nothing beneath a closed node // is reachable to be marked, which is why closing wipes. Closed Mark = iota // Open: this node's children show. Theirs follow their own marks, which // default to Closed -- so Open governs exactly one level. Open // OpenAll: this node and everything beneath it, until a deeper mark says // otherwise. It is a state and not an iteration: one mark, whatever the // size of the subtree. OpenAll )
type Marks ¶
type Marks struct {
// contains filtered or unexported fields
}
Marks is a tree's expansion: which nodes are open, held sparsely.
It lives on the SOURCE rather than on a data set, so two data sets over one descriptor cannot disagree about what the sequence contains. Two views sharing a tree share its expansion, which is sometimes exactly right; a view wanting its own wraps its own tree, which is cheap because wrapping is all it is.
The zero value is ready, with the top level showing and nothing deeper.
func (*Marks) Clear ¶
func (m *Marks) Clear()
Clear is collapse-all: the top level shows and nothing deeper does.
It is its own verb rather than a coincidence of the root's state. Setting the root Open would be a no-op where it is Open already, which is exactly when a hundred marks beneath it are the thing to be rid of.
func (*Marks) Close ¶
Close hides a node's children, and discards the expansion of everything held beneath it -- so collapsing a node and opening it again shows one level, not whatever was open before.
func (*Marks) Flat ¶
Flat reports whether every node beneath this one is closed: what this node's children inherit does not show, and nothing marked beneath it shows either.
**It is what lets a descent ask a level for a POSITION.** Where every row of a level stands for exactly one row of the flattening, the nth row of the level IS the nth row of that subtree -- so the level can be entered at a position rather than walked to it, and a reader a hundred thousand rows down costs one question instead of a hundred thousand rows. One open node anywhere beneath breaks that: its children stand between its siblings, and the arithmetic no longer holds.
It walks the marks and not the tree. What is held here is bounded by what somebody has TOUCHED, so this is a handful of nodes however large the sequence is -- the same property that makes Showing worth having.
func (*Marks) Held ¶
Held is how many nodes carry a mark of their OWN -- exceptions, not trie nodes. It is what "bounded by what somebody has touched" means when a test asks it, and the number that must not grow with the size of the tree.
func (*Marks) Mark ¶
Mark is a node's state: its own if it has one, and what it inherits if it has not.
The chain is the segments from the root down to it, which a descent has in hand -- it got there by walking them.
func (*Marks) Open ¶
Open makes a node's children show. Inside an OpenAll region this drops the node's Closed mark rather than adding an Open one, and the OpenAll resumes beneath it -- which is what somebody re-opening a folder they collapsed inside an expand-all expects to see.
The consequence worth naming: "open exactly one level, here, inside an OpenAll region" is a state this cannot express, because the verb that would say it is spent saying the other thing. It has not been wanted, and the alternative reading costs the interaction above, which is wanted constantly.
func (*Marks) Set ¶
Set puts a node into a state, and is the one mutator the three verbs are made of.
**Nothing happens where the state does not change.** A click on an already open node must not wipe what is beneath it, and asking for the state a node is already in is the commonest way that would happen.
**Where it does change, the subtree is wiped and the mark is only kept if it says something.** Those are the two rules, and they are applied in that order: the marks beneath were exceptions to the state being replaced, and a mark equal to what would be inherited is not an exception at all.
func (*Marks) Showing ¶
Showing calls back for every node whose children are VISIBLE, with the chain down to it and the state it is in.
**Only the ones actually reachable.** A mark is an exception to what it inherits, so a node marked Open inside a Closed parent does not show and neither does anything beneath it -- and yielding it would describe a subtree nobody can see. So the descent here is the shape the row descent has: into a node's children only where that node shows.
The root is not yielded. Its children are the top level, which a sequence has whether or not anything is marked; a caller that wants the root's own state asks `Mark()` with no segments.
It is for working out how LONG a flattening is without walking it: the top level counts itself, and every node that shows adds its children. What makes that worth having is the second rule up at the top of this file -- what is held is bounded by what somebody has touched, so this walks a handful of nodes and not a tree.
type Node ¶
A Node is a parent, as a node type sees it: what identifies it, what it holds, and where it stands.
The path is here because two of the three criteria are about it, and it is a STRING rather than a value because that is what a delimiter joins and a prefix bounds. Where a standing produces no path it is empty, and the criteria that use one are not the ones such a tree is built with.
type NodeType ¶
type NodeType struct {
// Source is where rows of this kind are read from. Nil is the tree's own
// source, which is the nested case: a hierarchy inside one body of records.
Source Source
// Children is how rows of this kind are found under a parent. The zero
// Criterion makes every node of this type a leaf, which is a legitimate
// kind for a row to be and is how a tree says "nothing hangs off this".
Children Criterion
// Standing is how a row of this kind says where it stands, and it belongs
// here rather than on the tree because it is a property of the SOURCE.
Standing Standing
// Then are the kinds the rows BENEATH this one are, by name. Empty is the
// default kind, which is what makes a tree of one shape need no names at
// all.
//
// **This is what lets a chain declare itself.** Without it, host ->
// application -> window needs every host row to carry `applications` and
// every application row to carry `windows` -- which means the applications
// SOURCE has to carry the view's type names as data. The kinds are the
// tree's own business, so the tree says them, and a row speaks up only where
// it departs from its kind.
//
// **It is a LIST because one parent can have two kinds of children.** A host
// has applications and it has volumes, out of two entirely different
// sources, and neither is a special case of the other. Each branch is asked
// for its own children of this parent, and they come back grouped in the
// order named -- which is predictable, is what a view usually wants (every
// folder, then every file), and asks nothing of the two sources that they
// cannot answer. Interleaving them would need a sort field the two sources
// share, and nothing says they have one.
//
// **And each branch may say WHEN it applies**, which is what makes a files
// list work: a `.zip` takes its children from the archive, a `.ini` from its
// sections, a folder from the listing, and a plain file has none. All four
// are rows of one kind, out of one source, with one column mapping -- what
// differs is decided by the row's own values, so it is a predicate and not a
// second kind.
Then []Branch
}
A NodeType is a KIND OF ROW: where rows of that kind come from, how one says where it stands, and what kind the rows beneath it are.
It was called a child type while the only thing it described was somebody's children, and the name was the parent's vantage point rather than the thing's own. A tree's parents are of a kind too -- a host row, an application row, a window row -- and anything a VIEW hangs off a type, a column mapping most of all, is about what a row IS and not about what hangs off it.
type NodeTypes ¶
type NodeTypes struct {
// Default is what a row that says nothing gets.
Default *NodeType
// Named are the others, by the name a row uses to ask for one.
Named map[string]*NodeType
// Field is the field a row OVERRIDES its children's kind in. Empty means no
// row can, and every level takes the kind its parent's type named.
//
// It is an override and no longer the only way, which is the difference the
// rename made: a row says something here when it is unusual -- a mount point
// under a folder, an alias, a graft -- and says nothing when it is not.
Field string
}
NodeTypes is the set a tree knows: one default, and any number named.
**That is what lets one tree mix kinds**: a host whose children are applications, an application whose children are windows, read out of three different places.
func (NodeTypes) Beneath ¶
Beneath are the kinds of the rows under this one: what its own type says comes next, unless the row itself says otherwise.
Four answers, and the middle two are the ones to get right:
- no type at all above, which is the top level: the DEFAULT.
- the field is absent, or undefined, which is a row saying nothing: the kinds its parent's type named. A field a record has not got reads as undefined everywhere in this library, so "says nothing" and "has not got it" are one case and must be.
- the field says `false` or `nil`: no children, whatever its siblings do.
- the field names a kind: that one alone -- or, where nothing is registered under the name, a leaf.
**An unknown name is a leaf and not a refusal.** One mistyped field must not empty a view, which is the same posture a sort takes towards a field a record has not got.
A row's override names ONE kind, where a type's Then may name several. A row departing from its kind is saying something unusual about itself, and wanting two unusual things at once has not come up; a type declaring the shape of a tree is the place where several is ordinary. It answers in NAMES rather than in types, because the name is what a reader of the flattened sequence needs: the descent knows a row's kind by construction -- whatever the `applications` criterion returned is an application -- and the name is how it says so, in the field the tree writes beside the depth.
type Notice ¶
type Notice struct {
Extent
Change Change
// Fields are the ones that may have changed, for Altered. A name that
// decides the sequence costs the order; one that does not costs those
// records' values and nothing structural. Naming none says the source
// cannot tell, which is every field.
Fields []string
}
A Notice is one thing a source says has happened to what is held.
The extent is by identity, the way everything here is. One record is First with no Last; a stretch is both, and is read in the order of the sequence the notice is answered against. Neither end is the whole of it -- every record the notice is answered against -- which is the widest thing a source can say and the most expensive.
type Placing ¶
type Placing interface {
Sink
// Place is one record's position, and what is known of it so far.
//
// **Its fields are true and its silence is not.** What is here can be
// believed, rendered and kept; what is missing is not a claim that the
// record has not got it. That is the whole difference between this and a
// subset, which says how many members there are and therefore how much it
// left out.
Place(id *Value, fields Record) error
// Placed says the ORDER is settled: every record of this scope has been
// named, under Place or under Record or Subset, and here is the same claim
// Done will carry.
//
// It comes after the last place and before Done, and only where it says
// something Done would not -- an answer with no places in it settles its
// order at the end like any other, and says so once. Which matters because
// a reader cannot lay out a sequence, not even one of placeholders, until
// it knows no further record will turn up between two it already holds.
Placed(c Complete)
}
A Placing sink takes PLACES as well as records: a record's identity, and whatever is known of it so far with no claim about how much that is.
It is the third degree of knowledge, beside a whole record and a subset that says how much it left out, and it is what lets an answer be started on before it is finished. What a reader needs first is almost never the values -- it is where the rows are. With the order it can lay its rows out and stay reactive under a scrub while the contents arrive behind them.
**Optional, and that is what makes it safe.** Places are ADDITIONAL, never substitutional: a sink that is not one of these is handed every record it would have been handed anyway, because whoever answers falls back to finding the values rather than to sending less. So there is nothing to negotiate -- a sink either has somewhere to put a place or it has not.
type Reading ¶
type Reading int
A Reading is how a record's contents are named. Both are useful and neither is a subset of the other's behaviour, so it is said once, when the source is made, rather than guessed per record.
const ( // Whole exposes the record entire. `key` is the document's own key for it // and `value` is its value, and every member wears a dot: `.size` is the // member called size, `.0` is the item at position 0. // // Nothing can shadow anything, so a member called `key` -- which the bundle // format's own `_bundle: (key: "figaro")` has -- is `.key` and is reachable // like any other. It is the reading for data whose records are not all the // same shape, and for anything that has to survive a round trip. // // `key` here is a field. It is what the document called this record, handy // to sort or show; what this end identifies the record by travels beside // the bag and is nobody's field. Whole Reading = iota // Members exposes the members alone, under their own names: `size`, not // `.size`. It is the shorter reading, and it suits a source whose records // are all lists of named fields -- which is most of them. // // It is deliberately not complete: the record's own key and value have no // name here, and positions have none either, a bare `0` being the number it // spells rather than a name. A member called `key` is a // member like any other and is reached and sent as one -- the point of this // reading is the document at its face value, and nothing in the bag is an // identity for it to collide with. Members )
type Record ¶
type Record []*Field
A Record is a run of fields.
func PSLFields ¶
PSLFields is what one PSL value carries, named the way a reading names them.
It is the record a document's member WOULD be, without a source to hold it: what the layer above needs when it takes a value out of one document and stands it in another's place.
func (Record) Field ¶
Field makes a Record a Subject, which is the common case: a record already in our own shape is tested as it stands.
func (Record) Get ¶
Get is the value under a name, or nil where the record does not name it. A field present with no value reads as nil too: a bare name is a name, not a value of its own.
type RecordCount ¶
type RecordCount struct {
// N is how many records there are, or where the count is not Exact, how
// many there are AT LEAST.
N int
// Exact says N is the whole figure rather than a floor.
Exact bool
}
How many records a sequence has.
Not how many were asked for and not how many came back -- a scope already knows both of those, having stated one and counted the other. This is the figure a reader needs to size a bar it has not scrolled: the whole of the sequence, which is to say the whole of the DATA SET.
It belongs to the filter, not to the order ¶
A data set is a source, a sort and a filter, and only two of those three can change this number. Sorting the same records cannot make there be more or fewer of them, and the fields a query asks for change what a scope carries rather than which records are in it.
So every data set over one source with one filter has the same count, and a reader that clicks a column header -- a new sort, a new order, every placement thrown away -- already knows it.
A floor is worth more than a silence ¶
Some sources know the figure for nothing: one that ordered its records when the sequence was opened has them in a slice, and the count is its length. Some cannot know it at all. And in between is the common case, where part of the sequence has been read and what is known is a LOWER BOUND -- which is most of what a bar wants anyway, and is exactly what an incremental reader has.
So a count is a number and whether that number is the whole story. Nothing known at all is a floor of zero, which is true of every sequence and says nothing, and is how a source that cannot count answers.
func AtLeast ¶
func AtLeast(n int) RecordCount
func CountOf ¶
func CountOf(v DataSet) RecordCount
CountOf is what a data set says its sequence holds, and Unknown for one that does not count.
func Exactly ¶
func Exactly(n int) RecordCount
Exactly and AtLeast are the two things that can be said, and Unknown is saying nothing -- a floor of zero, which holds for every sequence there is.
func Unknown ¶
func Unknown() RecordCount
func (RecordCount) Add ¶
func (c RecordCount) Add(n int) RecordCount
Add and Take are records certainly arriving and certainly leaving, which is what a notice about one identity says. Both keep whatever the figure was: a floor with one more record above it is a floor one higher, and an exact count that gains one is exact.
**This is why counting needs no deltas of its own.** A source reporting an append has already said +1 by saying Added, and one reporting a deletion has said -1; there is no second channel to invent and nothing to resynchronise, because the figure is only ever moved by a statement that was being sent anyway.
func (RecordCount) And ¶
func (c RecordCount) And(d RecordCount) RecordCount
And is two counts added, for a sequence made of several -- exact only where both halves are, because a floor plus an exact figure is still only a floor.
func (RecordCount) Doubt ¶
func (c RecordCount) Doubt(n int) RecordCount
Doubt is n records that MAY no longer be in the sequence -- replaced, or altered in a field the filter tests, either of which can take a record out of it or leave it where it was.
The true figure is then somewhere between N-n and N, so N-n is a floor and nothing here is exact any more. Which is the whole reason a floor is worth carrying: without one, a single doubtful record would cost the entire count, and the next honest thing to say would be nothing at all.
func (RecordCount) Nothing ¶
func (c RecordCount) Nothing() bool
Nothing reports whether this says anything at all.
func (RecordCount) String ¶
func (c RecordCount) String() string
String is the count as readable text, for a message or a test saying what it expected. Never parsed back.
func (RecordCount) Take ¶
func (c RecordCount) Take(n int) RecordCount
type Roles ¶
type Roles struct {
// Sort and Filter are the fields the SEQUENCE is decided by. A change to
// one of them can move a record, or take it out of the sequence
// altogether, so it costs membership or order and not merely a repaint.
Sort []string
Filter []string
// Detail is the rest of what the query asked for: fields that are carried
// and shown and decide nothing, so a change to one costs those records'
// values and nothing structural.
Detail []string
// Whole says the query asked for whole records, so its detail fields are
// every field a record has that is not a sort or a filter field -- which
// cannot be listed here, the records being the source's to shape. Detail is
// then what was asked to be LEFT OUT, and the answer to "is this a detail
// field" is yes for anything else.
Whole bool
}
Roles is the fields of a sequence grouped by the part each one plays.
A field may play two -- sorted and filtered both -- and appears in both groups when it does, because it costs both. What it may not do is be a detail field as well: a field that decides where a record stands is not decoration, however much it is also displayed.
func (Roles) Decides ¶
Decides reports whether a change to this field could move a record or take it out of the sequence.
Which is the SKELETON question: a field that decides where a record stands is what positions, membership, the count and the watermark are built out of, and losing it means the stretch has to be read again from the start. A field that decides nothing is flesh, and re-acquiring it is a fill for the rows somebody is actually looking at.
func (Roles) Filters ¶
Filters reports whether a change to this field could take a record OUT of the sequence, or bring one in.
Narrower than Decides, and the difference is exactly the sort. A sort field changing moves a record to another place in the sequence; it cannot make there be more or fewer of them. So this is the question the COUNT asks, where Decides is the one the order asks, and a sequence sorted by `.size` and filtered by `.kind` answers them differently about each.
func (Roles) Shows ¶
Shows reports whether this sequence carries the field without being decided by it -- so a change to it repaints those records and moves nothing.
A sequence that asked for whole records shows everything it is not decided by and has not excluded, which is why this is a question rather than a list.
type Row ¶
A Row is one record of a source that holds its records.
Field comes from Subject, which is what a filter tests: a field the row has not got reads as nil, which is `undefined` rather than an error.
Fields is the row entire. A format that computes its fields lazily -- the PSL reading does, reaching into a nested list only when asked -- pays for this one when a scope carries the whole record, and pays for nothing when the query named the fields it wanted.
type Scope ¶
type Scope struct {
// After is the record to start past: the asker holds it already. Nil
// starts at the first record in walk order.
After *Value
// Until is the record to stop before: the asker holds that one too, and
// everything beyond it, so a walk that reaches it has joined two runs the
// asker held separately. Nil walks until the count is reached or the
// records run out.
Until *Value
// Count is how many records are wanted.
Count int
// From is a position to start NEAR, for a reader that has a place in mind
// rather than a record: a scroll thumb dragged to the middle of a long
// sequence knows how far down it is and knows no identity there at all.
//
// **Best effort, and never a promise.** A source honours it as well as it
// can and says where it actually started in Complete.First, which is the
// truth whatever From asked for. One that holds its records lands exactly;
// one built on others estimates and may be well out; one that cannot place
// a position at all starts at the beginning and says so. So a reader that
// means a particular place asks, reads First, and asks again from what it
// learned -- which converges, and needs no source to promise anything.
//
// It is not a lie about identities. After and Until stay what they always
// were, and this says something weaker in its own words rather than
// dressing a position up as one of them.
//
// Zero is the beginning, which is where a scope starts anyway, so an unset
// From asks for nothing. After WINS over it: a reader holding the record it
// wants to carry on past knows something better than a position, and a
// scope naming both a record and a place is refused rather than quietly
// answered from one of them.
From int
// Reversed walks the sequence from its end rather than its beginning.
//
// Every level turns over, the one the sort does not write included: an
// identity settles what the named levels leave equal, and a sequence read
// backwards settles it backwards too. That is what makes this the exact
// mirror -- `size desc` turns one level over and leaves ties facing the way
// they were, which is a different sequence again.
//
// It belongs to the scope rather than the sequence because it costs
// nothing: one prepared ordering is read either way, where a reversed
// *sequence* would be a second ordering of the same records. And it names
// no field, so it is the one way to turn over a sequence whose records are
// read in a way that cannot name their identity at all.
Reversed bool
}
A Scope is the run of records a query asks for: where to start, which way to walk, how many, and where the asker's own knowledge picks up again.
It is not a filter and it names no field. The sequence is already decided by the descriptor, and a scope only says which part of it to read -- so a source prepares one ordering and serves every scope of it cheaply, rather than preparing a new one because the reader scrolled.
After and Until are identities, not positions. An identity means something only to the source that issued it, which is why a source made of several others never passes one down: it hands each of them that one's own.
type Sink ¶
type Sink interface {
// Ordered says the records about to arrive are in the sequence's order.
// It comes before the first of them or not at all, which is the only place
// it is worth anything: a sink that learns it afterwards can no longer act
// on the records it has already been given. Not being told means not
// ordered, which is always safe.
Ordered()
// Record takes one record entire: its identity, and every field it has.
//
// Whole is worth saying because it outlives the scope that asked for it.
// A record that arrived entire answers any question about that record, so
// whoever holds it can answer the next query out of it instead of asking
// again. It states no totals because it IS the totals: what it carries is
// everything there is.
//
// The identity is beside the fields, not among them. A record may well
// carry a field called `key`, and that field is data: it sorts, it
// filters, it fills a column. What names the record is this.
Record(id *Value, fields Record) error
// Subset takes some of a record: its identity, the fields that were asked
// for, and how many members the record HAS ALTOGETHER.
//
// The totals are what let a later question be answered without asking
// again. Knowing a record has eight named members and holding eight of them
// settles every other name at once -- there is nothing left for one to be --
// and knowing it has three ordered ones settles `3` and everything past it,
// an ordered member being named by its position. Without them a subset
// answers the question that asked for it and no other.
//
// **A field the record has not got is sent as undefined**, rather than left
// out. Left out it reads as a field nobody asked about; sent, it is a
// guarantee that the record has not got it, and it is never asked for
// again. It is not counted in the totals, being knowledge about the record
// and not a member of it.
Subset(id *Value, fields Record, has Totals) error
Done(c Complete)
}
A Sink takes an answer as it is produced: the records one at a time, and then what ended them.
One at a time because a scope of a million records need not be assembled anywhere before the first of them moves, and because a source whose records are across a connection has them in that shape already.
type SortLevel ¶
A SortLevel is one level of a sort: which field, which way, and -- for text -- under which collation.
type Source ¶
type Source interface {
// Open states a sequence: one filter, one sort. It is refused where the
// sequence cannot be produced exactly -- an op that is not implemented, a
// collation that is not carried -- because an ordering that is quietly a
// little different corrupts every answer after it and looks like data.
Open(descriptor *DataSetDescriptor) (DataSet, error)
}
A Source is a body of records that sequences can be read out of.
type Standing ¶
type Standing struct {
// Location is the field holding the row's CONTAINER -- where it lives, not
// what it is. With Name, a row's own path is the two joined.
//
// This is the field that makes children one equality, and the name is
// `location` rather than `path` for a reason: `path` can mean where a row
// lives or the row's own full address, and the two behave completely
// differently. Whatever the data calls it -- `directory`, `container`,
// `folder`, `thread` -- is what goes here.
Location string
// Name is the field holding this row's own segment. Empty means the
// record's key, rendered as text.
Name string
// Whole is the field holding the row's own full path, materialised. It
// suits data that already knows its whole address, and it is read as the
// record spells it.
Whole string
// Delimiter goes between segments: `/` for something filesystem-like, `.`
// for a namespace, `::`, whatever the data uses.
//
// **A segment containing it makes a path that means two things**, and that
// is the caller's to avoid exactly as a duplicate key is. Where the tree
// DERIVES a path, choosing one the segments do not contain is the whole of
// what keeps it unambiguous.
Delimiter string
}
A Standing says how a row of one source tells where it stands.
**It belongs to a CHILD TYPE and not to a tree.** A child type names a source, and how a row says where it stands is a property of that source rather than of whatever is reading it -- so a tree that is addresses at the top and an adjacency list beneath has two standings, and its capability degrades at the boundary rather than for the whole of it.
func (Standing) Check ¶
Check refuses a standing that cannot mean what it says.
Two ways to be wrong, and both are configuration rather than data: naming two standings at once, and asking for a path to be BUILT with nothing to build it out of. A standing that builds no path is not among them -- that is the adjacency list, and it is a shape and not a mistake.
func (Standing) ChildrenByLocation ¶
ChildrenByLocation is `eq <field> <the parent's own path>`: every row that says it LIVES here.
One equality, no depth field and no prefix arithmetic -- which is what a field holding the CONTAINER buys, and what a field holding a row's own full address cannot, no operator being able to take the parent off the front of one.
The path is compared as TEXT, because `eq` compares by kind and a location field holding a symbol or a number is a different value from the text of the same characters. A source whose location field is not text wants a different criterion, and gets a refusal from the filter rather than a wrong answer. It partitions for the same reason ChildrenByKey does -- a row lives in one place -- so one census of the source by the location field answers every node's twisty.
func (Standing) DescendantsByLocation ¶
DescendantsByLocation is the whole subtree in one question, deliberately.
**It is TWO predicates and not one, which is not what it looks like.** The obvious form -- `starts <field> <the parent's path, and a delimiter>` -- is not descendants at all: a direct child's location is the parent's path EXACTLY, with no delimiter after it, so a prefix test misses every child and catches only what is deeper. And dropping the delimiter to let them in drags `/usr/locally` into `/usr/local`, which is what appending it prevents.
So:
or { eq location "/usr/local" ; starts location "/usr/local/" }
The first half is the children, and is the same predicate ChildrenByLocation uses; the second is everything below them, bounded. Each half does exactly the job it was described as doing, and descendants are the two TOGETHER rather than either alone.
**It cannot be censused, and that is a property of the question rather than a gap.** A census partitions, putting each row in exactly one group; a subtree criterion puts every row in the group of every one of its ancestors. So there is no field whose values are these answers, and this one leaves the census parts out rather than counting something that is not what was asked.
func (Standing) Join ¶
Join puts a container and a name together.
**No trailing delimiter is assumed.** Data writes `/usr/local` and data writes `/usr/local/`, both are common, and one rule reads both: the delimiter goes between them and is not doubled where it is already there. So `/usr` and `local` join as `/usr/local`, `/usr/` and `local` join the same way, and a root spelled `/` does not produce `//usr`.
An empty container is the name alone, which is what the top level of a derived path wants: the first segment stands by itself rather than under a delimiter that leads nowhere.
func (Standing) PathOf ¶
PathOf is where this row stands, by whichever of the three readings is configured. `above` is the path of the row it was found beneath, which only the derived standing uses -- and which is exactly why the other two can say where a row belongs without having descended to it.
func (Standing) Paths ¶
Paths reports whether this standing produces a path at all. The zero Standing does not, and a tree over one keys its marks by identity instead.
func (Standing) Under ¶
Under is a path with the delimiter on it, for asking what lies beneath.
**This is where the missing trailing delimiter bites**, and it is why the tree appends one rather than hoping the data did. Descendants of `/usr/local` are `starts location "/usr/local/"` and NOT `starts location "/usr/local"`, because the second also matches `/usr/locally` -- a sibling whose name begins with the same letters, dragged into a subtree it has nothing to do with. The delimiter is what makes a prefix a BOUNDARY instead of a spelling.
Equality needs no such care, comparing the whole of the field, which is why only this one has a method.
The empty path stays empty: beneath the root is everything, and every string starts with nothing.
type Stop ¶
type Stop string
A Stop is why a scope ended, which the asker cannot work out for itself.
A scope that filled and one that ran out of records look identical from the far end -- both are a run of records that stopped -- and they mean opposite things about whether there is any point asking again.
const ( // StopFilled: the count was reached. There is more past the watermark. StopFilled Stop = "filled" // StopJoined: the walk reached `until`, so what the asker holds on this // side and what it holds on the other are now one run. StopJoined Stop = "joined" // StopExhausted: there are no more records this way. Nothing past the end // to be complete up to, so there is no watermark either. StopExhausted Stop = "exhausted" )
type Subject ¶
A Subject is anything a filter can take a field out of: the thing being tested, whatever shape it is held in.
An interface rather than a Record so that a source holding its records in its own form can put one to a filter without copying it into ours first -- which for a filter that rejects it would be a copy made for nothing.
A field the subject has not got reads as nil, which is `undefined`: a value with a rank of its own rather than an error. That is what makes a test against undefined a question about presence.
type Totals ¶
Totals is how many members a record has, whether or not they were sent.
Two counts and not one, because they settle different questions. ORDERED members are named by their position, so their count settles them entirely: n of them are the members `0` through `n-1`, and a query naming an index past that is answered without anyone being asked. NAMED members need the count AND the names -- knowing there are three says nothing about which three -- but the count still settles the question the moment three are known, there being nothing left for a fourth name to be.
**An absence does not count.** A member sent as undefined is a name the record has NOT got, said out loud so that nobody asks again. That is knowledge about the record rather than a member of it, and counting it would say the record had a member it has not.
type TreeFielded ¶
type TreeFielded interface {
TreeFields() TreeFields
}
A TreeFielded source says what names it writes its tree fields under.
Optional, on the model of Counting and Censusing: a source that is not a tree is not one of these, and a reader asking gets told so rather than having to guess from whether a field happens to be there. That difference matters -- "a tree that could not count this row's children" and "not a tree at all" are two answers, and sniffing for a field conflates them.
A wrapper over a tree may forward it, and one that does not simply reads as not a tree, which is a missing capability rather than a wrong answer.
type TreeFields ¶
type TreeFields struct {
Depth string // how deep the row stands, 0 at the top
Path string // where it stands, empty where the standing builds no path
Expandable string // how many children: a number, or a floor, or undefined
State string // `closed`, `open` or `openAll`, as a symbol
// Chain is the mark segments from the root down to this row, as a list of
// positional members -- the walk's own `mine`, written down.
//
// **It is what lets a reader hold a WINDOW of a tree and still open a row in
// it.** Expanding is `Marks.Open(chain...)`, and a reader that holds the whole
// pre-order can spell the chain for itself: the ancestors of any row precede
// it, so walking back up the rows it has is enough. A reader holding rows
// forty to eighty cannot -- the ancestors are above forty, which is exactly
// what it declined to hold -- so it would have to fetch what it let go
// in order to click on what it has.
//
// `Path` is this same fact for a level with a Standing, and is empty for the
// two commonest trees: a source that is its own adjacency list, and a flat
// source read as one generation. Neither configures a standing, so neither has
// a path, and both still have to be clickable.
//
// The descent holds the chain already, a segment appended per level, so the
// row costs one list and nothing is walked to find it.
Chain string
// Kind is the NAME of the node type this row is, as a symbol, and empty for
// the default kind.
//
// **This is how a reader tells one kind of row from another**, and nothing
// else can: the descent knows a row's kind by construction -- whatever the
// `applications` criterion returned out of the applications source is an
// application -- and this is where it says so. A view holding a column
// mapping per kind needs exactly this to know which mapping a row takes.
Kind string
}
TreeFields names the things a tree ADDS to every row.
They are the caller's to change because they shadow: a tree over filesystem records whose own field is called `path` would otherwise lose it, and the tree's own must win or a view could not draw. Moving the tree's name is the way out, and it is why these are not constants.
func TreeFieldsOf ¶
func TreeFieldsOf(src Source) (TreeFields, bool)
TreeFieldsOf asks a source what it writes its tree fields under, and reports false for one that is not a tree.
type TreeHint ¶
type TreeHint struct {
// Parent is the field holding the parent's key. A row with nothing under it
// stands at the top, `undefined` being what a record lacking a field reads
// as everywhere else.
Parent string
// Location is the field holding the container the row lives in -- where it
// lives, not what it is. Whatever the data calls it: `directory`,
// `container`, `folder`, `thread`.
Location string
// Root is how the TOP LEVEL's container is spelled, for a Location descent.
//
// It is here because only the author knows: data writes a root as `/`, as
// `.`, as the empty string, and as nothing at all. Left out, the top level is
// the rows whose container is **absent or empty** -- two predicates, because
// `undefined` and `""` are two values and both are ordinary ways to say "at
// the top".
Root string
// Name is the field holding the row's own segment. Empty means the record's
// key, rendered as text.
Name string
// Whole is the field holding the row's own full address, where it carries
// one. A path reading and never a descent -- see above.
Whole string
// Delimiter goes between segments, where a path is built or read.
Delimiter string
// Children is the field saying whether a row has children and how many:
// `undefined` or `false` is a leaf, `true` is children of unknown number, a
// number is that many. Empty means no row says, and every twisty is counted.
Children string
// Order is the field a row's place among its SIBLINGS comes from.
//
// It earns a field of its own because sibling order is so often not any
// datum's order: the order a document listed them in, the order a store
// decided about them. For a document whose records are positional, `key` is
// that order, the key of a positional record being its index.
Order string
// Label is the field holding the row's own name, for whatever draws it.
//
// It is about the record -- which of its fields is what this record is
// CALLED -- rather than about a column, and a reader with no use for it may
// ignore it.
Label string
}
A TreeHint is what a source says about the shape of its own records.
Every field is a FIELD NAME, not a value, and the zero hint says nothing.
func TreeHintOf ¶
TreeHintOf is what a source says about the shape of its records, and false for one that says nothing.
**Asking the SOURCE rather than being handed a hint beside it** is the same move TreeFieldsOf makes, and for the same reason: whatever produced the source is what knows, and a reader that has been given only a source should not have to have been given a second thing as well.
func (TreeHint) Check ¶
Check refuses a hint that cannot mean what it says.
Every one of these is CONFIGURATION rather than data, which is why it is worth finding when a hint is read rather than when a row is drawn: a document with a contradictory hint is a document to be fixed, and a tree assembled from it would be wrong in a way that looks like the data being wrong.
func (TreeHint) Options ¶
func (h TreeHint) Options(src Source) (TreeOptions, error)
Options is the tree this hint describes, over the records of one source.
**This is the whole payoff.** A hint is worth having because it becomes a configured tree without anybody restating it, so the assembling lives here, next to what a hint means, rather than in each of the readers.
type TreeOptions ¶
type TreeOptions struct {
// Source and DataSetDescriptor are the TOP LEVEL: where its rows come from and which of
// them, in what order. A nil DataSetDescriptor is all of them, unsorted.
Source Source
Descriptor *DataSetDescriptor
// Types is what kind each row is. **The top level's rows are the DEFAULT
// kind**, so where the top level's rows come from is here and what they ARE
// is there -- including how one says where it stands, which used to be said
// twice and is now said once, by the type.
Types NodeTypes
// SaysChildren is the field a row uses to say whether it has children and
// how many: `undefined` or `false` is a leaf, `true` is children of unknown
// number, and a number is that many. Empty means no row says, and every
// twisty is a count.
SaysChildren string
// Revisits is how many times a node may be EXPANDED again beneath itself on
// one root-to-leaf path: 0 refuses, which is the default, and 3 is the most
// that can be asked for. It is a setting because a tree that refuses says
// the data is a tree and one that allows says it is a graph, and seeing
// round the loop is how somebody understands it. See `docs/trees.md`.
//
// **It governs expansion and never emission.** A row the criterion says is
// a child IS a child, so a node standing on its own path is still drawn --
// with a dead twisty. Hiding it would make the tree lie about what is under
// a node, which is worse than showing a loop, and the budget exists to bound
// the walk rather than to censor the data.
Revisits int
// ByPath identifies rows by their PATH rather than by the record's own key.
//
// Not the default, and a choice a caller makes knowing why. A record's
// identity is unique across a tree nested inside ONE source, and a path is
// longer than a key. Where a tree grafts a second source under rows of the
// first, or allows a node to stand beneath itself, two rows can carry one
// key and the path is what tells them apart.
ByPath bool
// Fields names what the tree adds. Empty names take TreeFieldsDefault.
Fields TreeFields
}
TreeOptions is everything a tree is made of.
type TreeSource ¶
type TreeSource struct {
// contains filtered or unexported fields
}
A TreeSource presents the visible rows of a hierarchy as one flat sequence.
func NewTreeSource ¶
func NewTreeSource(o TreeOptions) (*TreeSource, error)
NewTreeSource makes one, and refuses what cannot be used.
The checks are configuration and are worth finding here rather than when a row is drawn: a standing that names two readings, named node types with no field to name them in, and a sort on the top level, which the next paragraph is about.
func (*TreeSource) Collapse ¶
func (t *TreeSource) Collapse(chain ...string)
func (*TreeSource) CollapseAll ¶
func (t *TreeSource) CollapseAll()
func (*TreeSource) Expand ¶
func (t *TreeSource) Expand(chain ...string)
Expand, ExpandAll, Collapse and CollapseAll are the mark verbs, and each tells every live sequence afterwards.
**Invalidation is told, never decided.** Nothing here polls, nothing expires and no generation is compared: a mark moved, so the source says so, and the sequences drawing on it rebuild. That the saying costs a rebuild is this version's price for an eager flattening, and it is bounded by the rows that are visible rather than by the size of the tree.
func (*TreeSource) ExpandAll ¶
func (t *TreeSource) ExpandAll(chain ...string)
func (*TreeSource) MarkedByPath ¶
func (t *TreeSource) MarkedByPath(kind string) bool
MarkedByPath reports whether one KIND of row's mark segment is its path rather than its identity.
**A chain handed to Expand has to be spelled the way the walk spells it**, and the walk spells a level with a standing by path -- see `descent.level`, and `Standing.Paths`, which is where the two answers are decided. A caller reaching in from the side has neither in hand, so it asks.
It is per kind because a standing is: a tree of applications under hosts descends by key at one level and might descend by address at the next, and there is one right answer per level rather than one per tree.
Without this a reader guesses, and the guess is wrong exactly where it is hard to see: a location-descended tree drew its twisties from the child counts, took an Expand keyed by identity, matched nothing, and opened nothing -- with no error anywhere, because a chain naming a node that is not there is an ordinary thing to ask about.
func (*TreeSource) Marks ¶
func (t *TreeSource) Marks() *Marks
Marks is the expansion, for a caller that wants to set it directly. The tree's own four verbs are the usual way, because they also tell the sequences that what they hold has changed.
func (*TreeSource) Open ¶
func (t *TreeSource) Open(descriptor *DataSetDescriptor) (DataSet, error)
Open states a sequence over the visible rows.
**A sort is refused**, because the order is the tree's own and is BUILT rather than sorted. It does not fall out of CompareLevels either: that stops where the shorter run ends and returns 0, so `[a]` and `[a, b]` compare EQUAL rather than parent-before-child, and a tuple per level cannot express a varying-depth path. Each LEVEL is sorted, by its own descriptor, and the pre-order is laid over that.
A filter is the SHALLOW one: it is asked of the rows at every level, and a parent that does not match is gone and its children with it. Deep filtering -- keeping a parent that does not match where a descendant does -- is eager by nature and is not here yet.
func (*TreeSource) SortBy ¶
func (t *TreeSource) SortBy(byKind map[string][]SortLevel)
SortBy restates how each KIND of row is ordered among its siblings, and tells every sequence stated over this tree.
**A tree sorts LEVEL by level, which is why this is per kind and not one order.** The pre-order is built rather than sorted -- `Open` refuses a sort for that reason -- so "sort by size" over a tree is a sort of each level's own sequence, laid out in the order the walk visits them. A kind spelling its size `bytes` where another spells it `size` is exactly the case, and the caller who knows both is the one holding the columns.
A kind not named here is ordered as its configuration says. A kind named with no levels is ordered the way its source answers, which is how a sort is turned OFF -- so the map's keys are the question and an empty slice is an answer.
The empty name is the default kind, which is the top level's.
func (*TreeSource) Stale ¶
func (t *TreeSource) Stale()
Stale says that what this tree flattens has changed: a level's source was restated, a record was altered, one arrived or one went.
**Told, never decided.** A tree reads several sources at several levels and holds the flattening; nothing here asks any of them whether they still say what they said. Whoever changed one says so, and every sequence stated over this tree is built again.
**It takes no Notice, because a tree's flattening is total.** The pre-order is one walk over every level, so a record altered anywhere can change which rows are visible, how deep they stand and what their twisties say -- there is no run of one level kept apart from the rest for a reason to narrow. Taking the fields would be taking a parameter this version does not read. Narrowing the walk is what a later one would want a Notice for, and it can have one then.
func (*TreeSource) TreeFields ¶
func (t *TreeSource) TreeFields() TreeFields
TreeFields is what this source writes its added fields under.
func (*TreeSource) WhenArrived ¶
func (t *TreeSource) WhenArrived(tell func())
WhenArrived adds a reader to be told once a flattening has completed (serval.Arriving).
What a reader of a tree wants to know is that the ROWS are there, which is a different moment from a level answering: one level of several has said its piece and the walk goes on. So this fires when the walk is done, and nothing before.
type Value ¶
type Value struct {
Kind Kind
Str string // SymbolValue, TextValue, BytesValue
Int int64 // NumberValue, when IsInt
Num float64 // NumberValue, otherwise
IsInt bool // NumberValue: written with no fractional part, and it fits
Bool bool // BoolValue
List Record // ListValue
}
A Value is one value of a record.
The fields a kind does not use are not read and carry no meaning. Str serves the three kinds that are a run of characters -- a symbol's name, text, and bytes as they stand -- because they differ in what they MEAN and not in how they are held.
func NewNil ¶
func NewNil() *Value
The constructors. A value is built, never parsed: whatever read the text owns the reading of it.
func Val ¶
Val is a Go value as a Value, for the callers that have one of a handful of ordinary types and do not want to say which. Anything it does not know becomes undefined rather than a guess.
func (*Value) String ¶
String is a value as readable text, for an error message, a log line or a test that wants to say what it expected in one line.
Readable and not canonical: it is for a person, it is never parsed back, and nothing turns on it. Key is what tables are keyed by and Equal is what decides whether two values are the same one. The shape -- names and values separated by spaces inside braces -- is shared with Record and Filter so that one glance reads all three.
Source Files
¶
- amended.go
- amendorder.go
- arriving.go
- cache.go
- cached.go
- cachedrecord.go
- cachedscope.go
- census.go
- compare.go
- composed.go
- coverage.go
- delimited.go
- identity.go
- invalidate.go
- list.go
- marks.go
- match.go
- nodetype.go
- place.go
- psl.go
- query.go
- reckon.go
- record.go
- recordcount.go
- source.go
- tree.go
- treehint.go
- treepath.go
- value.go
- wrapping.go