func selectClientFields(ctx context.Context, query *gorm.DB, fieldMask *pbtypes.FieldMask) *gorm.DB {
	if len(fieldMask.GetPaths()) == 0 {
		return query.Preload("Attributes")
	}
	var clientColumns []string
	var notFoundPaths []string
	for _, path := range ttnpb.TopLevelFields(fieldMask.GetPaths()) {
		switch path {
		case "ids", "created_at", "updated_at", "deleted_at":
		case attributesField:
			query = query.Preload("Attributes")
		default:
			if columns, ok := clientColumnNames[path]; ok {
				clientColumns = append(clientColumns, columns...)
			} else {
				notFoundPaths = append(notFoundPaths, path)
			}
		}
	}
	if len(notFoundPaths) > 0 {
		warning.Add(ctx, fmt.Sprintf("unsupported field mask paths: %s", strings.Join(notFoundPaths, ", ")))
	}
	return query.Select(cleanFields(append(append(modelColumns, "deleted_at", "client_id"), clientColumns...)...))
}
selectClientFields selects relevant fields (based on fieldMask) and preloads details if needed.
package store
import (
	"context"
	"fmt"
	"reflect"
	"runtime/trace"
	"strings"
	pbtypes "github.com/gogo/protobuf/types"
	"github.com/jinzhu/gorm"
	"go.thethings.network/lorawan-stack/v3/pkg/rpcmiddleware/warning"
	"go.thethings.network/lorawan-stack/v3/pkg/ttnpb"
)
func GetClientStore(db *gorm.DB) ClientStore {
	return &clientStore{store: newStore(db)}
}
type clientStore struct {
	*store
}