v1.0.0: Initial implementation#2
Merged
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the initial model implementation by expanding core Model functionality (sorting, mapping/filtering/reducing, merging, JSON marshal/unmarshal, iterators) and modernizing types/comments (e.g., any and Go doc comments).
Changes:
- Added/expanded model operations: sort (by key/value + reverse), merge, map/filter/reduce, and iterator improvements.
- Refactored internal typing from
interface{}toanyand improved error propagation in import/unmarshal paths. - Updated tests/examples and module dependency on
github.com/bdlm/cast/v2.
Reviewed changes
Copilot reviewed 12 out of 13 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| value.go | Switches internal storage/API returns to any and converts block comments to Go doc comments. |
| model.types.go | Introduces a generic-ish ModelData type constraint. |
| model.sorter.go | Reworks sorting implementation; adds Len, Reverse, and value-comparison helpers. |
| model.marshaler.go | Adds locking during marshal and improves unmarshal/import error handling; updates UnmarshalModel signature/behavior. |
| model.iterator.go | Updates iterator APIs to any and improves list Seek validation. |
| model.importer.go | Refactors import helpers to return errors and uses any-typed containers. |
| model.go | Expands core Model API (New accepts initial data, GetData copies out state, adds Map/Filter/Reduce/Merge, adds read-only enforcement, etc.). |
| model_test.go | Updates construction/signatures and fixes an assertion. |
| interface.marshaler.go | Converts block comments to doc comments; updates UnmarshalModel docs/signature. |
| go.mod | Bumps github.com/bdlm/cast/v2 dependency version. |
| examples_test.go | Updates usage to new New(..., nil) and GetData(). |
| errors.go | Adds additional error definitions and converts header comment to doc comment style. |
| .gitignore | Expands ignore patterns (but includes duplicated entries). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
58
to
64
| if stdModel.ModelTypeList == mdl.GetType() { | ||
| k := key.(int) | ||
| if k > len(mdl.data) { | ||
| k := cast.To[int](key) | ||
| if k < 0 || k >= len(mdl.data) { | ||
| return errors.WrapE(InvalidIndex, errors.Errorf("index '%d' out of range", k)) | ||
| } | ||
| mdl.data = append(mdl.data[:key.(int)-1], mdl.data[key.(int):]...) | ||
| mdl.data = append(mdl.data[:k], mdl.data[k+1:]...) | ||
| return nil |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Initial stable release of
github.com/bdlm/model.Overview
bdlm/modelis a generic, concurrent-safe data container for Go. A singleModelholds either a hash (string-keyed, ordered map) or a list(integer-indexed array) of arbitrary values. Values are wrapped in a
Valuetype that provides typed accessors. Nested models are supported at arbitrary
depth; JSON unmarshaling builds the nested structure automatically.
Core API
Construction
New(modelType, data) (*Model, error)— creates a HASH or LIST model,optionally pre-populated from
map[string]anyor[]any. Hash models builtvia
NeworUnmarshalJSONare automatically sorted by key.CRUD
Set(key, value) error— store a value by key; hash keys accept any typeand are cast to
stringviabdlm/cast.Get(key) (Value, error)— retrieve a value by key or index.Has(key) bool— check existence without retrieving.Push(value) error— append to a LIST model.Delete(key) error— remove by key or index; hash index is rebuiltatomically and the backing-array slot is zeroed to release the GC reference.
Len() int— number of elements.Metadata
GetType() / SetType()— model type (HASH or LIST); type can only bechanged while the model is empty.
GetID() / SetID()— arbitrary model identifier; used as the primary sortkey when comparing nested models.
GetData() ([]any, map[string]int, map[int]string)— returns isolatedcopies of the internal data slice and both index maps.
SetData(data) error— replaces the entire data store atomically.Locking
Lock()— makes the model permanently read-only; there is no Unlock.All write operations return
ReadOnlyModelon a locked model.Iteration
Bidirectional cursor iterator:
Next(pK, pV *any) bool— advance; resets and returns false at end.Prev(pK, pV *any) bool— retreat; clamps to -1 and returns false at start.Cur(pK, pV *any) bool— read current position without moving.Seek(pos any) error— jump to a key (HASH) or index (LIST).Reset()— reset cursor to before the first element.The cursor is reset to -1 on any successful mutation (Delete, SetData, Sort,
Reverse) and is left unchanged on failed operations.
Sorting
Sort(SortFlag)sorts in place. Usessync.RWMutexwrite lock; does not resetthe cursor unless data ordering actually changes.
Sort flags (
github.com/bdlm/std/v2/sorter):SortByValue0Sort(SortByValue)is a no-op. Trigger value sorting withSortAsc,SortDesc, orSortAsString.SortByKey1SortAsString.SortAsc2SortByKey.SortDesc4SortByKey.SortAsString8SortByKey.SortReverse16Only one invalid combination:
SortAsc | SortDesc.Type-stratified value ordering (ascending):
*Model < nil < bool < numeric < string < other.Reverse() error— reverse in place; rebuilds hash index maps correctly.Functional Operations
All three operate on a snapshot taken before the callback is invoked, so
callbacks may safely read or write the model without deadlocking.
Filter(func(Value) bool) Model— returns a new model of the same typecontaining only elements for which the callback returns true.
Map(func(Value) Value) Model— returns a new model with each elementreplaced by the callback's return value.
Reduce(func(carry, cur Value) Value) Value— iteratively reduces to asingle value; the first element is the initial carry. Returns nil for an
empty model.
Merge
Merge(incoming Model) errormerges all values fromincominginto thereceiver.
Self-merge returns
InvalidMethodContext.JSON
MarshalJSON() / UnmarshalJSON()— standardencoding/jsoninterfaces.UnmarshalJSONbuilds into a temporary model and swaps internals under asingle write lock, so concurrent readers never observe an empty intermediate
state. Repeated calls replace data rather than accumulating.
MarshalModel() / UnmarshalModel()—Marshaler/Unmarshalerinterfacemethods.
UnmarshalModeltreats the JSONnullliteral as a no-op.Value Accessors
Valuewrapsanyand exposes:Bool,Int,Float,Float32,Float64,String,Value(raw),Model(nested model),List([]stdModel.Value),Map(map[string]stdModel.Value).All numeric/string conversions use
bdlm/cast; they return an error when theconversion is not possible.
Package-level generics
To[T]andToE[T]expose the cast helpers directly.Error Sentinels
All errors are compatible with the standard
errors.Isfunction:InvalidIndexInvalidIndexTypeInvalidMethodContextReadOnlyModelInvalidDataSetInvalidSortFlagCombinationConcurrency
All public methods are safe for concurrent use. The implementation uses
sync.RWMutex— read operations (Get,Has,Len,Cur,GetData,MarshalJSON) acquire a read lock and run concurrently; write operationsacquire an exclusive lock. The
lockedflag and model type are stored assync/atomicvalues. The double-checked locking pattern is used on all writepaths to close the TOCTOU window between the pre-lock check and lock
acquisition.
Dependencies
bdlm/cast/v2bdlm/errors/v2bdlm/std/v2Model,Value,Iterator,Sorter