Tier: Platform · Status: Full · Java original:
firefly-common-data(R2DBC) · .NET project:FireflyFramework.Data
data provides the persistence abstractions every Firefly service
shares — a generic filter DSL that renders to parameterised SQL, a
canonical Page[T] paged-result envelope, and a typed Repository[T,K]
contract with an in-memory implementation for tests. A pgx-backed
implementation is on the v26.06 roadmap; until then, services that
talk to PostgreSQL define their own typed repository conforming to
the Repository[T, K] interface.
type Page[T any] struct {
Content []T
Number int // zero-based page index
Size int
TotalElements int64
TotalPages int
}
func NewPage[T any](content []T, number, size int, total int64) Page[T]
func Empty[T any]() Page[T]The wire-shape is identical to the Java/.NET Page<T> so SDK clients
dispatch on the same JSON.
type Op string // OpEq | OpNe | OpLt | OpLte | OpGt | OpGte | OpLike | OpILike | OpIn | OpIsNil
type Predicate struct { Field string; Op Op; Value any }
type Sort struct { Field string; Direction Direction } // Asc | Desc
type Filter struct {
Predicates []Predicate
Sorts []Sort
Page int
Size int
}
func (*Filter) Where(field, value) *Filter
func (*Filter) Add(Predicate) *Filter
func (*Filter) OrderBy(field, dir) *Filter
func (*Filter) Paged(page, size) *Filter
func (Filter) ToSQL() (string, []any) // -> " WHERE …", []any{…}ToSQL renders a parameterised PostgreSQL fragment using $1, $2,
… argument placeholders. Identifier quoting is double-quoted.
type Repository[T any, K comparable] interface {
FindByID(ctx context.Context, id K) (T, error)
Find(ctx context.Context, f Filter) (Page[T], error)
Save(ctx context.Context, entity T) (T, error)
Delete(ctx context.Context, id K) error
}
var ErrNotFound = errors.New("firefly/data: not found")In-process implementation of Repository, parameterised on a
user-supplied keyer func(T) K. Honours paging; does not honour
predicates (use a SQL-backed Repository for filtering).
import (
"context"
"github.com/fireflyframework/fireflyframework-go/data"
)
type User struct { ID, Name string }
repo := data.NewMemoryRepository[User, string](func(u User) string { return u.ID })
_, _ = repo.Save(ctx, User{ID: "u1", Name: "alice"})
f := data.Filter{}
f.Where("name", "alice").OrderBy("id", data.Asc).Paged(0, 10)
page, _ := repo.Find(ctx, f)For a real Postgres-backed repository, implement the Repository
interface against pgx.Conn / *sql.DB, using f.ToSQL() to render
the WHERE / ORDER BY / LIMIT clauses.
cd data
go test ./...Covers Page total-pages math, every Op rendering correctly,
predicate ↔ argument index mapping with OpIsNil skipping arg slots,
and the in-memory repository's CRUD + paging.