feat(sieve): add sieve module with Map

This commit is contained in:
2026-10-11 14:22:56 +02:00
parent b906bdd48b
commit 6933004b87
4 changed files with 103 additions and 0 deletions

56
modules/sieve/README.md Normal file
View File

@@ -0,0 +1,56 @@
# sieve
Generic, dependency-free collection helpers that the standard library slices and maps packages lack: mapping, filtering, reducing, keying, grouping, deduplicating, partitioning and finding, plus a small set type.
`import "git.golem15.com/golem15/summercms/modules/sieve"`
**Name:** A sand sieve: you shake a collection through it and keep what you need; map, filter and reduce for slices and maps.
## Overview
`sieve` gives plain Go slices the collection operations that WinterCMS code reaches for on Laravel collections. Every function is eager and never modifies its input, results never share a backing array with the input, callbacks run once per element in input order, and nil or empty input yields a non-nil empty result, so `encoding/json` writes `[]` rather than `null`.
## Role in the framework
A dependency-free leaf with no imports, so any module, plugin or application can use it without import cycles.
## Features
- `sieve.Map` applies a function to every element and returns the results in order; with a field accessor it is the pluck operation.
## Usage
```go
package blog
import "git.golem15.com/golem15/summercms/modules/sieve"
type Post struct {
ID int
Title string
}
func titles(posts []Post) []string {
return sieve.Map(posts, func(p Post) string { return p.Title })
}
```
## API reference
| Identifier | Description |
|------------|-------------|
| `sieve.Map` | Returns f applied to each element, in input order. Nil input gives a non-nil empty slice. |
## Dependencies
- SummerCMS modules: none.
- Third-party: none.
- Standard library: none (the package has no imports).
## Testing
```sh
go test ./modules/sieve/...
```
The tests are in-memory and need no external services.

View File

@@ -0,0 +1,24 @@
package sieve_test
import (
"fmt"
"git.golem15.com/golem15/summercms/modules/sieve"
)
type post struct {
ID int
Title string
}
func ExampleMap() {
posts := []post{
{ID: 1, Title: "Hello"},
{ID: 2, Title: "Summer"},
{ID: 3, Title: "Goodbye"},
}
// Pluck the titles with a field accessor.
titles := sieve.Map(posts, func(p post) string { return p.Title })
fmt.Println(titles)
// Output: [Hello Summer Goodbye]
}

22
modules/sieve/sieve.go Normal file
View File

@@ -0,0 +1,22 @@
// Package sieve provides generic, dependency-free collection helpers that the
// standard library slices and maps packages lack.
//
// Every function is eager and never modifies its input. Results never share a
// backing array with the input, so changing or appending to a result leaves the
// caller's slice unchanged. Callbacks run once per element, in input order.
// Nil or empty input yields a non-nil empty slice or map, so encoding/json
// writes [] or {} rather than null.
package sieve
// Map returns a new slice holding f applied to each element of s, in order.
// f is called once per element. A nil or empty s yields a non-nil empty slice.
//
// Map is also the pluck operation: pass an accessor func to extract one field
// from every element, for example the titles of a slice of posts.
func Map[S ~[]T, T, U any](s S, f func(T) U) []U {
out := make([]U, 0, len(s))
for _, v := range s {
out = append(out, f(v))
}
return out
}