From abae73ef1e10aac5332895b1c13ed7fd61b54711 Mon Sep 17 00:00:00 2001 From: adlerhurst <27845747+adlerhurst@users.noreply.github.com> Date: Fri, 13 Jun 2025 11:59:22 +0200 Subject: [PATCH] this is the proposal i mentioned in the review --- backend/v3/domain/instance.go | 2 +- backend/v3/storage/database/database.go | 8 +++ .../storage/database/dialect/postgres/rows.go | 49 ++++++++++++++++++- 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/backend/v3/domain/instance.go b/backend/v3/domain/instance.go index 82e6ac451f..acbee10c1b 100644 --- a/backend/v3/domain/instance.go +++ b/backend/v3/domain/instance.go @@ -87,7 +87,7 @@ type InstanceRepository interface { // Member() MemberRepository Get(ctx context.Context, opts ...database.Condition) (*Instance, error) - List(ctx context.Context, opts ...database.Condition) ([]Instance, error) + List(ctx context.Context, opts ...database.Condition) ([]*Instance, error) Create(ctx context.Context, instance *Instance) error Update(ctx context.Context, condition database.Condition, changes ...database.Change) (int64, error) diff --git a/backend/v3/storage/database/database.go b/backend/v3/storage/database/database.go index f94037eaa5..a04aff4993 100644 --- a/backend/v3/storage/database/database.go +++ b/backend/v3/storage/database/database.go @@ -61,3 +61,11 @@ type Row interface { type Rows interface { pgx.Rows } + +// Collector is an interface for collecting rows into a specific type. +type Collector[T any] interface { + // Collect collects a single row into the specified type. + Collect(Row) (T, error) + // CollectRows collects multiple rows into a slice of the specified type. + CollectRows(Rows) ([]T, error) +} diff --git a/backend/v3/storage/database/dialect/postgres/rows.go b/backend/v3/storage/database/dialect/postgres/rows.go index 7a36979a5e..8dafc88f4f 100644 --- a/backend/v3/storage/database/dialect/postgres/rows.go +++ b/backend/v3/storage/database/dialect/postgres/rows.go @@ -1,11 +1,58 @@ package postgres import ( + "github.com/georgysavva/scany/v2/pgxscan" "github.com/jackc/pgx/v5" "github.com/zitadel/zitadel/backend/v3/storage/database" ) -var _ database.Rows = (*Rows)(nil) +var ( + _ database.Rows = (*Rows)(nil) + _ database.CollectableRows = (*Rows)(nil) +) type Rows struct{ pgx.Rows } + +// Collect implements [database.CollectableRows]. +// See [this page](https://github.com/georgysavva/scany/blob/master/dbscan/doc.go#L8) for additional details. +func (r *Rows) Collect(dest any) (err error) { + defer func() { + closeErr := r.Close() + if err == nil { + err = closeErr + } + }() + return pgxscan.ScanAll(dest, r.Rows) +} + +// CollectFirst implements [database.CollectableRows]. +// See [this page](https://github.com/georgysavva/scany/blob/master/dbscan/doc.go#L8) for additional details. +func (r *Rows) CollectFirst(dest any) (err error) { + defer func() { + closeErr := r.Close() + if err == nil { + err = closeErr + } + }() + return pgxscan.ScanRow(dest, r.Rows) +} + +// CollectExactlyOneRow implements [database.CollectableRows]. +// See [this page](https://github.com/georgysavva/scany/blob/master/dbscan/doc.go#L8) for additional details. +func (r *Rows) CollectExactlyOneRow(dest any) (err error) { + defer func() { + closeErr := r.Close() + if err == nil { + err = closeErr + } + }() + return pgxscan.ScanOne(dest, r.Rows) +} + +// Close implements [database.Rows]. +// Subtle: this method shadows the method (Rows).Close of Rows.Rows. +func (r *Rows) Close() error { + r.Rows.Close() + return nil +}