From 46eb76d91ba98a2293a8c2c7a160628daa81460b Mon Sep 17 00:00:00 2001 From: Michael Kenney Date: Thu, 21 May 2026 22:33:10 -0600 Subject: [PATCH 1/7] v2.1.1: Model interface cleanup --- .gitignore | 12 ++++++++++++ model/model.go | 33 ++++++++++++++++++++++----------- sorter/sorter.go | 19 +++++++++++++++---- 3 files changed, 49 insertions(+), 15 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3d8971c --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +/vendor +_* +go.sum +go.sum +go.work +vendor/ +_* +benchmark* +.claude* +claude* +CLAUDE* +coverage* diff --git a/model/model.go b/model/model.go index 8438c46..d661fec 100644 --- a/model/model.go +++ b/model/model.go @@ -4,12 +4,13 @@ package model type ModelType int const ( - // ModelTypeList causes the model to behave as a list (keys are unsigned, - // contiguous integers beginning at 0). - ModelTypeList ModelType = iota - // ModelTypeHash causes the model to behave as a hash (keys are strings, + // HASH causes the model to behave as a hash (keys are strings, // order is static). - ModelTypeHash + HASH ModelType = iota + + // LIST causes the model to behave as a list (keys are unsigned, + // contiguous integers beginning at 0). + LIST ) // Model is a list or a map of Values. @@ -23,9 +24,11 @@ type Model interface { Delete(key interface{}) error // Filter filters elements of the data using a callback function and // returns the result. - Filter(callback func(Value) Model) Model + Filter(callback func(Value) bool) Model // Get returns the specified data value in this model. Get(key interface{}) (Value, error) + // GetData returns the current data set and indexes. + GetData() ([]interface{}, map[string]int, map[int]string) // GetID returns returns this model's id. GetID() interface{} // GetType returns the model type. @@ -36,22 +39,30 @@ type Model interface { Lock() // Map applies a callback to all elements in this model and returns the // result. - Map(callback func(Value) Model) Model + Map(callback func(Value) Value) Model // Merge merges data from any Model into this Model. Merge(Model) error // Push a value to the end of the internal data store. Push(value interface{}) error - // Reduce iteratively reduces the data set to a single value using a - // callback function and returns the result. - Reduce(callback func(Value) bool) Value + // Reduce iteratively reduces the data to a single value using a callback + // function and returns the result. + // + // The callback function takes two `Value` arguments, the first being the + // carry value from the previous iteration (or the first element for the + // first iteration) and the second being the current element. The callback + // returns a `Value` which becomes the carry value for the next iteration. + // After all iterations, Reduce returns the final carry value. + Reduce(callback func(carry, cur Value) Value) Value // Set stores a value in the internal data store. All values must be // identified by key. Set(key interface{}, value interface{}) error // SetData replaces the current data stored in the model with the // provided data. SetData(data interface{}) error + // Reverse reverses the order of the data store. + Reverse() error // SetID sets this Model's identifier property. - SetID(id interface{}) + SetID(id interface{}) error // SetType sets the model type. If any data is stored in this model, // this property becomes read-only. SetType(typ ModelType) error diff --git a/sorter/sorter.go b/sorter/sorter.go index bc77933..321a0ef 100644 --- a/sorter/sorter.go +++ b/sorter/sorter.go @@ -1,17 +1,28 @@ package sorter // SortFlag provides a type for sort flags -type SortFlag int +type SortFlag uint const ( - // SortByKey - sort hash data by key - SortByKey SortFlag = iota + // SortByKey - sort hash data by key. + SortByKey SortFlag = 1 << iota + + // SortByValue - sort data by value using type-stratified comparison: + // nil < bool < numeric < string < other. + SortByValue + + // SortAsString - when sorting data use string comparison via cast. This is + // a tiebreak for SortByValue and the default for SortByKey. + SortAsString + + // SortReverse - reverse the order of the data set after sorting. + SortReverse ) // Sorter describes a sorter. type Sorter interface { // Reverse reverses the order of the data set. - Reverse(SortFlag) error + Reverse() error // Sort sorts the model data. Sort(SortFlag) error // Len returns the number of items stored in this model. From 9c70c5477b6196534422b520d4773550cc621cb5 Mon Sep 17 00:00:00 2001 From: Michael Kenney Date: Thu, 21 May 2026 22:49:07 -0600 Subject: [PATCH 2/7] v2.1.1: Sorter flags --- sorter/sorter.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sorter/sorter.go b/sorter/sorter.go index 321a0ef..fb32ee4 100644 --- a/sorter/sorter.go +++ b/sorter/sorter.go @@ -11,6 +11,12 @@ const ( // nil < bool < numeric < string < other. SortByValue + // SortAsc - sort data in ascending order. This is the default. + SortAsc + + // SortDesc - sort data in descending order. + SortDesc + // SortAsString - when sorting data use string comparison via cast. This is // a tiebreak for SortByValue and the default for SortByKey. SortAsString From 395c6006d6faf0db6820358f6ad22ab90af8169b Mon Sep 17 00:00:00 2001 From: Michael Kenney Date: Fri, 22 May 2026 23:57:19 -0600 Subject: [PATCH 3/7] Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- model/model.go | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/model/model.go b/model/model.go index d661fec..1827285 100644 --- a/model/model.go +++ b/model/model.go @@ -27,9 +27,20 @@ type Model interface { Filter(callback func(Value) bool) Model // Get returns the specified data value in this model. Get(key interface{}) (Value, error) - // GetData returns the current data set and indexes. + // GetData returns snapshots of the current data set and indexes. + // + // Implementations must not expose internal slice or map storage directly; + // the returned slice and maps must be safe for the caller to read and + // modify without affecting the model's internal state. + // + // The return values are: + // - data: a snapshot of the model's values in model order. + // - keyToIndex: a snapshot of hash keys to indexes for HASH models; nil + // for LIST models. + // - indexToKey: a snapshot of indexes to hash keys for HASH models; nil + // for LIST models. GetData() ([]interface{}, map[string]int, map[int]string) - // GetID returns returns this model's id. + // GetID returns this model's id. GetID() interface{} // GetType returns the model type. GetType() ModelType @@ -52,6 +63,11 @@ type Model interface { // first iteration) and the second being the current element. The callback // returns a `Value` which becomes the carry value for the next iteration. // After all iterations, Reduce returns the final carry value. + // + // For a non-empty model, the first element is used as the initial carry, + // so the callback is first invoked with that carry and the second + // element. For an empty model, Reduce returns nil and does not invoke the + // callback. Reduce(callback func(carry, cur Value) Value) Value // Set stores a value in the internal data store. All values must be // identified by key. @@ -62,6 +78,10 @@ type Model interface { // Reverse reverses the order of the data store. Reverse() error // SetID sets this Model's identifier property. + // + // It returns an error if the model is read-only (for example, after + // Lock has been called) or if id is invalid or of an unsupported type + // for the implementation. SetID(id interface{}) error // SetType sets the model type. If any data is stored in this model, // this property becomes read-only. From 01882fb7bd7cb3c2838f146770acb2cd24643da2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 23 May 2026 05:58:16 +0000 Subject: [PATCH 4/7] fix: make SortByValue the default sort flag Agent-Logs-Url: https://github.com/bdlm/std/sessions/7b912a44-cd8b-4ba6-897c-b5791ceb555c Co-authored-by: mkenney <477514+mkenney@users.noreply.github.com> --- sorter/sorter.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sorter/sorter.go b/sorter/sorter.go index fb32ee4..1794b44 100644 --- a/sorter/sorter.go +++ b/sorter/sorter.go @@ -4,12 +4,12 @@ package sorter type SortFlag uint const ( - // SortByKey - sort hash data by key. - SortByKey SortFlag = 1 << iota - // SortByValue - sort data by value using type-stratified comparison: - // nil < bool < numeric < string < other. - SortByValue + // nil < bool < numeric < string < other. This is the default/zero value. + SortByValue SortFlag = 0 + + // SortByKey - sort hash data by key. + SortByKey SortFlag = 1 << (iota - 1) // SortAsc - sort data in ascending order. This is the default. SortAsc From 85ccc15222fd450b09d3211268e434ffe1d58767 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 23 May 2026 05:59:07 +0000 Subject: [PATCH 5/7] refactor: make sorter flag values explicit Agent-Logs-Url: https://github.com/bdlm/std/sessions/7b912a44-cd8b-4ba6-897c-b5791ceb555c Co-authored-by: mkenney <477514+mkenney@users.noreply.github.com> --- sorter/sorter.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sorter/sorter.go b/sorter/sorter.go index 1794b44..fd98967 100644 --- a/sorter/sorter.go +++ b/sorter/sorter.go @@ -9,20 +9,20 @@ const ( SortByValue SortFlag = 0 // SortByKey - sort hash data by key. - SortByKey SortFlag = 1 << (iota - 1) + SortByKey SortFlag = 1 << 0 // SortAsc - sort data in ascending order. This is the default. - SortAsc + SortAsc SortFlag = 1 << 1 // SortDesc - sort data in descending order. - SortDesc + SortDesc SortFlag = 1 << 2 // SortAsString - when sorting data use string comparison via cast. This is // a tiebreak for SortByValue and the default for SortByKey. - SortAsString + SortAsString SortFlag = 1 << 3 // SortReverse - reverse the order of the data set after sorting. - SortReverse + SortReverse SortFlag = 1 << 4 ) // Sorter describes a sorter. From b18e6648c1a13cc535cb2a445ff1ce01ec6216ca Mon Sep 17 00:00:00 2001 From: Michael Kenney Date: Fri, 22 May 2026 23:59:15 -0600 Subject: [PATCH 6/7] fix package name --- errors/error.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/errors/error.go b/errors/error.go index bb44660..2b07943 100644 --- a/errors/error.go +++ b/errors/error.go @@ -1,4 +1,4 @@ -package error +package errors import ( "github.com/bdlm/std/v2/caller" From fcd8ecc14879524695002804a4866693d107aab7 Mon Sep 17 00:00:00 2001 From: Michael Kenney Date: Sat, 23 May 2026 04:06:47 -0600 Subject: [PATCH 7/7] changelog --- CHANGELOG.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 673382f..e33598c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,26 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - **Minor**: feature additions, removal of deprecated features - **Patch**: bug fixes, backward compatible protobuf model changes, etc. +# v2.2.0 - 2026-05-23 +#### Added +* `model.Model.GetData()` — returns snapshots of the data set and key/index maps; implementations must not expose internal storage directly +* `model.Model.Reverse()` — reverses the order of the data store +* `sorter.SortByValue` — zero-value `SortFlag`; type-stratified sort (nil < bool < numeric < string < other); now the default sort behavior +* `sorter.SortAsc`, `SortDesc`, `SortAsString`, `SortReverse` — explicit bitflag sort options +* `.gitignore` + +#### Changed +* `model.ModelTypeHash` / `model.ModelTypeList` renamed to `model.HASH` / `model.LIST`; order swapped so `HASH` is the zero/iota value +* `model.Model.Filter` callback signature changed from `func(Value) Model` to `func(Value) bool` +* `model.Model.Map` callback signature changed from `func(Value) Model` to `func(Value) Value` +* `model.Model.Reduce` callback signature changed from `func(Value) bool` to `func(carry, cur Value) Value` (standard fold semantics) +* `model.Model.SetID` now returns `error` +* `sorter.SortFlag` underlying type changed from `int` to `uint` +* `sorter.Sorter.Reverse` signature changed from `Reverse(SortFlag) error` to `Reverse() error` + +#### Fixed +* `errors/error.go` package declaration corrected from `package error` to `package errors` + # v2.1.0 - 2020-05-30 #### Added * `Caller` package