Skip to content
Snippets Groups Projects
Select Git revision
  • 998f3e84ba73b241740a404d097d2b7c65cd352a
  • master default protected
  • feature/PRXS-3383-CollectionsSort
  • feature/2781-SpacesLoggingMiddleware
  • feature/PRXS-3421-ImplementNewRefAPI
  • feature/PRXS-3143-3235-ReferenceOptions
  • feature/PRXS-3143-LimitReferenceFields
  • feature/PRXS-3234-FeaturePruneIdents
  • PRXS-3421-RecursiveReferences
  • feature/3109-SerializeFeature
  • release/0.33
  • feature/3109-RecoverySchema
  • feature/3109-feature
  • fix/PRXS-3369-ValidateFields
  • refactor/PRXS-3306-MovePkgGroup1
  • refactor/6-pkg-refactor-expr
  • fix/PRXS-3360-TemplateBuilderPatch
  • feature/3293-MongoV2
  • feature/3272-GoVersionUp
  • feature/PRXS-3218-HideTemplateActions
  • feature/PRXS-3234-PruneIdents
  • v0.33.1
  • v0.32.0
  • v0.31.1
  • v0.31.0
  • v0.30.0
  • v0.29.0
  • v0.28.0
  • v0.27.0-alpha.1+16
  • v0.27.0-alpha.1+15
  • v0.27.0-alpha.1+14
  • v0.27.0-alpha.1+13
  • v0.27.0-alpha.1+12
  • v0.27.0-alpha.1+11
  • v0.27.0-alpha.1+10
  • v0.27.0-alpha.1+9
  • v0.27.0-alpha.1+8
  • v0.27.0-alpha.1+7
  • v0.27.0-alpha.1+6
  • v0.27.0-alpha.1+5
  • v0.27.0-alpha.1+4
41 results

extension.go

Blame
  • options.go 20.36 KiB
    package items
    
    import (
    	"maps"
    	"slices"
    
    	"git.perx.ru/perxis/perxis-go/pkg/options"
    	pb "git.perx.ru/perxis/perxis-go/proto/items"
    )
    
    type Options struct {
    	Env               map[string]interface{}
    	Filter            []string
    	PermissionsFilter []string
    }
    
    func MergeOptions(opts ...Options) Options {
    	o := Options{
    		Env:    make(map[string]interface{}),
    		Filter: make([]string, 0),
    	}
    
    	for _, opt := range opts {
    
    		for k, v := range opt.Env {
    			o.Env[k] = v
    		}
    
    		o.Filter = append(o.Filter, opt.Filter...)
    		o.PermissionsFilter = append(o.PermissionsFilter, opt.PermissionsFilter...)
    	}
    
    	return o
    }
    
    type CreateOptions struct {
    	Options
    
    	UpdateAttrs bool
    }
    
    func MergeCreateOptions(opts ...*CreateOptions) *CreateOptions {
    	o := &CreateOptions{}
    	for _, opt := range opts {
    		if opt == nil {
    			continue
    		}
    		if opt.UpdateAttrs {
    			o.UpdateAttrs = true
    		}
    
    		o.Options = MergeOptions(o.Options, opt.Options)
    	}
    	return o
    }
    
    func CreateOptionsToProto(opts ...*CreateOptions) *pb.CreateOptions {
    	if opts == nil {
    		return nil
    	}
    	o := MergeCreateOptions(opts...)
    	return &pb.CreateOptions{
    		UpdateAttrs: o.UpdateAttrs,
    	}
    }
    
    func CreateOptionsFromProto(opts *pb.CreateOptions) *CreateOptions {
    	if opts == nil {
    		return nil
    	}
    	return &CreateOptions{
    		UpdateAttrs: opts.UpdateAttrs,
    	}
    }
    
    type IntrospectOptions struct {
    	Options
    }
    
    func MergeIntrospectOptions(opts ...*IntrospectOptions) *IntrospectOptions {
    	o := &IntrospectOptions{}
    	for _, opt := range opts {
    		if opt == nil {
    			continue
    		}
    		o.Options = MergeOptions(o.Options, opt.Options)
    	}
    	return o
    }
    
    type GetOptions struct {
    	Options
    
    	// Язык перевода, который будет использоваться. Если не указан, то возвращаются данные для языка по умолчанию
    	LocaleID string
    
    	// Список идентификаторов переводов/локалей, которых должны быть включены в результат
    	TranslationsIDs []string
    }
    
    func MergeGetOptions(opts ...*GetOptions) *GetOptions {
    	o := &GetOptions{}
    	for _, opt := range opts {
    		if opt == nil {
    			continue
    		}
    		o.Options = MergeOptions(o.Options, opt.Options)
    		if opt.LocaleID != "" {
    			o.LocaleID = opt.LocaleID
    		}
    		o.TranslationsIDs = append(o.TranslationsIDs, opt.TranslationsIDs...)
    	}
    	return o
    }
    
    func GetOptionsToProto(opts ...*GetOptions) *pb.GetOptions {
    	if opts == nil {
    		return nil
    	}
    	o := MergeGetOptions(opts...)
    	return &pb.GetOptions{
    		LocaleId:        o.LocaleID,
    		TranslationsIds: o.TranslationsIDs,
    	}
    }
    
    func GetOptionsFromProto(opts *pb.GetOptions) *GetOptions {
    	if opts == nil {
    		return nil
    	}
    	return &GetOptions{
    		LocaleID:        opts.LocaleId,
    		TranslationsIDs: opts.TranslationsIds,
    	}
    }
    
    type FindOptions struct {
    	Options
    	options.FindOptions
    
    	Deleted   bool
    	Regular   bool
    	Hidden    bool
    	Templates bool
    
    	// Язык перевода, который будет использоваться. Если не указан, то возвращаются данные для языка по умолчанию
    	LocaleID string
    
    	// Список идентификаторов переводов/локалей, которых должны быть включены в результат
    	TranslationsIDs []string
    }
    
    func NewFindOptions(opts ...interface{}) *FindOptions {
    	fo := &FindOptions{}
    	fo.FindOptions = *options.MergeFindOptions(opts...)
    	return fo
    }
    
    func MergeFindOptions(opts ...*FindOptions) *FindOptions {
    	o := NewFindOptions()
    	for _, opt := range opts {
    		if opt == nil {
    			continue
    		}
    		o.Regular = o.Regular || opt.Regular
    		o.Templates = o.Templates || opt.Templates
    		o.Hidden = o.Hidden || opt.Hidden
    		o.Deleted = o.Deleted || opt.Deleted
    		o.Options = MergeOptions(o.Options, opt.Options)
    		o.FindOptions = *options.MergeFindOptions(&o.FindOptions, &opt.FindOptions)
    		if opt.LocaleID != "" {
    			o.LocaleID = opt.LocaleID
    		}
    		o.TranslationsIDs = append(o.TranslationsIDs, opt.TranslationsIDs...)
    	}
    	return o
    }
    
    func FindOptionsToProto(opts ...*FindOptions) *pb.FindOptions {
    	if opts == nil {
    		return nil
    	}
    	o := MergeFindOptions(opts...)
    	return &pb.FindOptions{
    		Deleted:         o.Deleted,
    		Regular:         o.Regular,
    		Hidden:          o.Hidden,
    		Templates:       o.Templates,
    		LocaleId:        o.LocaleID,
    		TranslationsIds: o.TranslationsIDs,
    		Options:         options.FindOptionsToPB(&o.FindOptions),
    	}
    }
    
    func FindOptionsFromProto(opts *pb.FindOptions) *FindOptions {
    	if opts == nil {
    		return nil
    	}
    	o := &FindOptions{
    		Deleted:         opts.Deleted,
    		Regular:         opts.Regular,
    		Hidden:          opts.Hidden,
    		Templates:       opts.Templates,
    		LocaleID:        opts.LocaleId,
    		TranslationsIDs: opts.TranslationsIds,
    	}
    	if fo := options.FindOptionsFromPB(opts.Options); fo != nil {
    		o.FindOptions = *fo
    	}
    	return o
    }
    
    type UpdateOptions struct {
    	Options
    
    	UpdateAttrs bool
    }
    
    func MergeUpdateOptions(opts ...*UpdateOptions) *UpdateOptions {
    	o := &UpdateOptions{}
    	for _, opt := range opts {
    		if opt == nil {
    			continue
    		}
    		if opt.UpdateAttrs {
    			o.UpdateAttrs = true
    		}
    
    		o.Options = MergeOptions(o.Options, opt.Options)
    	}
    	return o
    }
    
    func UpdateOptionsToProto(opts ...*UpdateOptions) *pb.UpdateOptions {
    	if opts == nil {
    		return nil
    	}
    	o := MergeUpdateOptions(opts...)
    	return &pb.UpdateOptions{
    		UpdateAttrs: o.UpdateAttrs,
    	}
    }
    
    func UpdateOptionsFromProto(opts *pb.UpdateOptions) *UpdateOptions {
    	if opts == nil {
    		return nil
    	}
    	return &UpdateOptions{
    		UpdateAttrs: opts.UpdateAttrs,
    	}
    }
    
    type DeleteOptions struct {
    	Options
    
    	UpdateAttrs bool
    	Erase       bool
    }
    
    func MergeDeleteOptions(options ...*DeleteOptions) *DeleteOptions {
    	o := &DeleteOptions{}
    	for _, opt := range options {
    		if opt == nil {
    			continue
    		}
    		if opt.UpdateAttrs {
    			o.UpdateAttrs = true
    		}
    		if opt.Erase {
    			o.Erase = true
    		}
    
    		o.Options = MergeOptions(o.Options, opt.Options)
    	}
    	return o
    }
    
    func DeleteOptionsToProto(opts ...*DeleteOptions) *pb.DeleteOptions {
    	if opts == nil {
    		return nil
    	}
    	o := MergeDeleteOptions(opts...)
    	return &pb.DeleteOptions{
    		UpdateAttrs: o.UpdateAttrs,
    		Erase:       o.Erase,
    	}
    }
    
    func DeleteOptionsFromProto(opts *pb.DeleteOptions) *DeleteOptions {
    	if opts == nil {
    		return nil
    	}
    	return &DeleteOptions{
    		UpdateAttrs: opts.UpdateAttrs,
    		Erase:       opts.Erase,
    	}
    }
    
    type SoftDeleteOptions struct {
    	Options
    }
    
    func MergeSoftDeleteOptions(opts ...*SoftDeleteOptions) *SoftDeleteOptions {
    	o := &SoftDeleteOptions{}
    	for _, opt := range opts {
    		if opt == nil {
    			continue
    		}
    		o.Options = MergeOptions(o.Options, opt.Options)
    	}
    	return o
    }
    
    type UndeleteOptions struct {
    	Options
    
    	UpdateAttrs bool
    }
    
    func MergeUndeleteOptions(opts ...*UndeleteOptions) *UndeleteOptions {
    	o := &UndeleteOptions{}
    	for _, opt := range opts {
    		if opt == nil {
    			continue
    		}
    		if opt.UpdateAttrs {
    			o.UpdateAttrs = true
    		}
    
    		o.Options = MergeOptions(o.Options, opt.Options)
    	}
    	return o
    }
    
    type PublishOptions struct {
    	Options
    
    	UpdateAttrs bool
    }
    
    func MergePublishOptions(opts ...*PublishOptions) *PublishOptions {
    	o := &PublishOptions{}
    	for _, opt := range opts {
    		if opt == nil {
    			continue
    		}
    		if opt.UpdateAttrs {
    			o.UpdateAttrs = true
    		}
    
    		o.Options = MergeOptions(o.Options, opt.Options)
    	}
    	return o
    }
    
    type UnpublishOptions struct {
    	UpdateAttrs bool
    
    	Options
    }
    
    func MergeUnpublishOptions(opts ...*UnpublishOptions) *UnpublishOptions {
    	o := &UnpublishOptions{}
    	for _, opt := range opts {
    		if opt == nil {
    			continue
    		}
    		if opt.UpdateAttrs {
    			o.UpdateAttrs = true
    		}
    
    		o.Options = MergeOptions(o.Options, opt.Options)
    	}
    	return o
    }
    
    type GetPublishedOptions struct {
    	Options
    
    	// Язык перевода, который будет использоваться. Если не указан, то возвращаются данные для языка по умолчанию
    	LocaleID string
    
    	// Список идентификаторов переводов/локалей, которых должны быть включены в результат
    	TranslationsIDs []string
    }
    
    func (opts *GetPublishedOptions) ToGetOptions() *GetOptions {
    	return &GetOptions{
    		Options:         MergeOptions(opts.Options),
    		LocaleID:        opts.LocaleID,
    		TranslationsIDs: slices.Clone(opts.TranslationsIDs),
    	}
    }
    
    func NewGetPublishedOptions(oo ...interface{}) *GetPublishedOptions {
    	fo := &GetPublishedOptions{}
    	for _, o := range oo {
    		switch o := o.(type) {
    		case string:
    			fo.LocaleID = o
    		case []string:
    			fo.TranslationsIDs = o
    		}
    	}
    	return fo
    }
    
    func MergeGetPublishedOptions(opts ...*GetPublishedOptions) *GetPublishedOptions {
    	o := &GetPublishedOptions{}
    	for _, opt := range opts {
    		if opt == nil {
    			continue
    		}
    		o.Options = MergeOptions(o.Options, opt.Options)
    		if opt.LocaleID != "" {
    			o.LocaleID = opt.LocaleID
    		}
    		o.TranslationsIDs = append(o.TranslationsIDs, opt.TranslationsIDs...)
    	}
    	return o
    }
    
    func GetPublishedOptionsToProto(opts ...*GetPublishedOptions) *pb.GetPublishedOptions {
    	if opts == nil {
    		return nil
    	}
    	o := MergeGetPublishedOptions(opts...)
    	return &pb.GetPublishedOptions{
    		LocaleId:        o.LocaleID,
    		TranslationsIds: o.TranslationsIDs,
    	}
    }
    
    func GetPublishedOptionsFromProto(opts *pb.GetPublishedOptions) *GetPublishedOptions {
    	if opts == nil {
    		return nil
    	}
    	return &GetPublishedOptions{
    		LocaleID:        opts.LocaleId,
    		TranslationsIDs: opts.TranslationsIds,
    	}
    }
    
    type FindPublishedOptions struct {
    	Options
    	options.FindOptions
    
    	Deleted   bool
    	Regular   bool
    	Hidden    bool
    	Templates bool
    
    	// Язык перевода, который будет использоваться. Если не указан, то возвращаются данные для языка по умолчанию
    	LocaleID string
    
    	// Список идентификаторов переводов/локалей, которых должны быть включены в результат
    	TranslationsIDs []string
    }
    
    func (opts *FindPublishedOptions) ToFindOptions() *FindOptions {
    	return &FindOptions{
    		Options:         MergeOptions(opts.Options),
    		FindOptions:     *options.MergeFindOptions(opts.FindOptions),
    		Deleted:         opts.Deleted,
    		Regular:         opts.Regular,
    		Hidden:          opts.Hidden,
    		Templates:       opts.Templates,
    		LocaleID:        opts.LocaleID,
    		TranslationsIDs: slices.Clone(opts.TranslationsIDs),
    	}
    }
    
    func NewFindPublishedOptions(opts ...interface{}) *FindPublishedOptions {
    	fo := &FindPublishedOptions{}
    	for _, o := range opts {
    		switch o := o.(type) {
    		case string:
    			fo.LocaleID = o
    		}
    	}
    
    	fo.FindOptions = *options.MergeFindOptions(opts...)
    	return fo
    }
    
    func MergeFindPublishedOptions(opts ...*FindPublishedOptions) *FindPublishedOptions {
    	o := NewFindPublishedOptions()
    	for _, opt := range opts {
    		if opt == nil {
    			continue
    		}
    		o.Regular = o.Regular || opt.Regular
    		o.Templates = o.Templates || opt.Templates
    		o.Hidden = o.Hidden || opt.Hidden
    		o.Options = MergeOptions(o.Options, opt.Options)
    		o.FindOptions = *options.MergeFindOptions(&o.FindOptions, &opt.FindOptions)
    
    		if opt.LocaleID != "" {
    			o.LocaleID = opt.LocaleID
    		}
    		o.TranslationsIDs = append(o.TranslationsIDs, opt.TranslationsIDs...)
    	}
    	return o
    }
    
    func FindPublishedOptionsToProto(opts ...*FindPublishedOptions) *pb.FindPublishedOptions {
    	if opts == nil {
    		return nil
    	}
    	o := MergeFindPublishedOptions(opts...)
    	return &pb.FindPublishedOptions{
    		Regular:         o.Regular,
    		Hidden:          o.Hidden,
    		Templates:       o.Templates,
    		LocaleId:        o.LocaleID,
    		TranslationsIds: o.TranslationsIDs,
    		Options:         options.FindOptionsToPB(&o.FindOptions),
    	}
    }
    
    func FindPublishedOptionsFromProto(opts *pb.FindPublishedOptions) *FindPublishedOptions {
    	if opts == nil {
    		return nil
    	}
    	o := &FindPublishedOptions{
    		Regular:         opts.Regular,
    		Hidden:          opts.Hidden,
    		Templates:       opts.Templates,
    		LocaleID:        opts.LocaleId,
    		TranslationsIDs: opts.TranslationsIds,
    	}
    	if fo := options.FindOptionsFromPB(opts.Options); fo != nil {
    		o.FindOptions = *fo
    	}
    	return o
    }
    
    type GetRevisionOptions struct {
    	Options
    
    	// Язык перевода, который будет использоваться. Если не указан, то возвращаются данные для языка по умолчанию
    	LocaleID string
    
    	// Список идентификаторов переводов/локалей, которых должны быть включены в результат
    	TranslationsIDs []string
    }
    
    func MergeGetRevisionOptions(opts ...*GetRevisionOptions) *GetRevisionOptions {
    	o := &GetRevisionOptions{}
    	for _, opt := range opts {
    		if opt == nil {
    			continue
    		}
    		o.Options = MergeOptions(o.Options, opt.Options)
    
    		if opt.LocaleID != "" {
    			o.LocaleID = opt.LocaleID
    		}
    		o.TranslationsIDs = append(o.TranslationsIDs, opt.TranslationsIDs...)
    	}
    	return o
    }
    
    func GetRevisionOptionsToProto(opts ...*GetRevisionOptions) *pb.GetRevisionOptions {
    	if opts == nil {
    		return nil
    	}
    	o := MergeGetRevisionOptions(opts...)
    	return &pb.GetRevisionOptions{
    		LocaleId:        o.LocaleID,
    		TranslationsIds: o.TranslationsIDs,
    	}
    }
    
    func GetRevisionOptionsFromProto(opts *pb.GetRevisionOptions) *GetRevisionOptions {
    	if opts == nil {
    		return nil
    	}
    	o := &GetRevisionOptions{
    		LocaleID:        opts.LocaleId,
    		TranslationsIDs: opts.TranslationsIds,
    	}
    	return o
    }
    
    type ListRevisionsOptions struct {
    	Options
    	options.FindOptions
    
    	// Язык перевода, который будет использоваться. Если не указан, то возвращаются данные для языка по умолчанию
    	LocaleID string
    
    	// Список идентификаторов переводов/локалей, которых должны быть включены в результат
    	TranslationsIDs []string
    }
    
    func MergeListRevisionsOptions(opts ...*ListRevisionsOptions) *ListRevisionsOptions {
    	o := &ListRevisionsOptions{}
    	for _, opt := range opts {
    		if opt == nil {
    			continue
    		}
    		o.Options = MergeOptions(o.Options, opt.Options)
    		o.FindOptions = *options.MergeFindOptions(&o.FindOptions, &opt.FindOptions)
    
    		if opt.LocaleID != "" {
    			o.LocaleID = opt.LocaleID
    		}
    		o.TranslationsIDs = append(o.TranslationsIDs, opt.TranslationsIDs...)
    	}
    	return o
    }
    
    func ListRevisionsOptionsToProto(opts ...*ListRevisionsOptions) *pb.ListRevisionsOptions {
    	if opts == nil {
    		return nil
    	}
    	o := MergeListRevisionsOptions(opts...)
    	return &pb.ListRevisionsOptions{
    		Offset:          int32(o.Offset),
    		Limit:           int32(o.Limit),
    		Fields:          o.Fields,
    		ExcludeFields:   o.ExcludeFields,
    		LocaleId:        o.LocaleID,
    		TranslationsIds: o.TranslationsIDs,
    	}
    }
    
    func ListRevisionsOptionsFromProto(opts *pb.ListRevisionsOptions) *ListRevisionsOptions {
    	if opts == nil {
    		return nil
    	}
    	fo := options.New(int(opts.Offset), int(opts.Limit))
    	fo.FieldOptions = options.FieldOptions{
    		Fields:        opts.Fields,
    		ExcludeFields: opts.ExcludeFields,
    	}
    	return &ListRevisionsOptions{
    		FindOptions:     *fo,
    		LocaleID:        opts.LocaleId,
    		TranslationsIDs: opts.TranslationsIds,
    	}
    }
    
    type ArchiveOptions struct {
    	Options
    }
    
    func MergeArchiveOptions(opts ...*ArchiveOptions) *ArchiveOptions {
    	o := &ArchiveOptions{}
    	for _, opt := range opts {
    		if opt == nil {
    			continue
    		}
    		o.Options = MergeOptions(o.Options, opt.Options)
    	}
    	return o
    }
    
    type FindArchivedOptions struct {
    	Options
    	options.FindOptions
    
    	// Язык перевода, который будет использоваться. Если не указан, то возвращаются данные для языка по умолчанию
    	LocaleID string
    
    	// Список идентификаторов переводов/локалей, которых должны быть включены в результат
    	TranslationsIDs []string
    }
    
    func NewFindArchivedOptions(oo ...interface{}) *FindArchivedOptions {
    	fo := &FindArchivedOptions{}
    	fo.FindOptions = *options.MergeFindOptions(oo...)
    	return fo
    }
    
    func MergeFindArchivedOptions(opts ...*FindArchivedOptions) *FindArchivedOptions {
    	o := NewFindArchivedOptions()
    	for _, opt := range opts {
    		if opt == nil {
    			continue
    		}
    		o.Options = MergeOptions(o.Options, opt.Options)
    		o.FindOptions = *options.MergeFindOptions(o.FindOptions, opt.FindOptions)
    
    		if opt.LocaleID != "" {
    			o.LocaleID = opt.LocaleID
    		}
    		o.TranslationsIDs = append(o.TranslationsIDs, opt.TranslationsIDs...)
    	}
    	return o
    }
    
    func FindArchivedOptionsToProto(opts ...*FindArchivedOptions) *pb.FindArchivedOptions {
    	if opts == nil {
    		return nil
    	}
    	o := MergeFindArchivedOptions(opts...)
    	return &pb.FindArchivedOptions{
    		LocaleId:        o.LocaleID,
    		TranslationsIds: o.TranslationsIDs,
    		Options:         options.FindOptionsToPB(&o.FindOptions),
    	}
    }
    
    func FindArchivedOptionsFromProto(opts *pb.FindArchivedOptions) *FindArchivedOptions {
    	if opts == nil {
    		return nil
    	}
    	o := &FindArchivedOptions{
    		LocaleID:        opts.LocaleId,
    		TranslationsIDs: opts.TranslationsIds,
    	}
    	if fo := options.FindOptionsFromPB(opts.Options); fo != nil {
    		o.FindOptions = *fo
    	}
    	return o
    }
    
    type GetArchivedOptions struct {
    	Options
    
    	// Язык перевода, который будет использоваться. Если не указан, то возвращаются данные для языка по умолчанию
    	LocaleID string
    
    	// Список идентификаторов переводов/локалей, которых должны быть включены в результат
    	TranslationsIDs []string
    }
    
    func MergeGetArchivedOptions(opts ...*GetArchivedOptions) *GetArchivedOptions {
    	o := &GetArchivedOptions{}
    	for _, opt := range opts {
    		if opt == nil {
    			continue
    		}
    		o.Options = MergeOptions(o.Options, opt.Options)
    
    		if opt.LocaleID != "" {
    			o.LocaleID = opt.LocaleID
    		}
    		o.TranslationsIDs = append(o.TranslationsIDs, opt.TranslationsIDs...)
    	}
    	return o
    }
    
    func GetArchivedOptionsToProto(opts ...*GetArchivedOptions) *pb.GetArchivedOptions {
    	if opts == nil {
    		return nil
    	}
    	o := MergeGetArchivedOptions(opts...)
    	return &pb.GetArchivedOptions{
    		LocaleId:        o.LocaleID,
    		TranslationsIds: o.TranslationsIDs,
    	}
    }
    
    func GetArchivedOptionsFromProto(opts *pb.GetArchivedOptions) *GetArchivedOptions {
    	if opts == nil {
    		return nil
    	}
    	o := &GetArchivedOptions{
    		LocaleID:        opts.GetLocaleId(),
    		TranslationsIDs: opts.GetTranslationsIds(),
    	}
    	return o
    }
    
    type UnarchiveOptions struct {
    	Options
    }
    
    func MergeUnarchiveOptions(opts ...*UnarchiveOptions) *UnarchiveOptions {
    	o := &UnarchiveOptions{}
    	for _, opt := range opts {
    		if opt == nil {
    			continue
    		}
    		o.Options = MergeOptions(o.Options, opt.Options)
    	}
    	return o
    }
    
    type AggregateOptions struct {
    	Options
    	options.SortOptions
    
    	// Fields поля которые должны быть возвращены или вычислены в результате.
    	// Ключ (string) - имя поля под которым будет добавляться результат.
    	// Значение (string) - является выражением, вычисление которого сформирует результат
    	// Функции для выражений (для поля F, типа T):
    	// - distinct(F) - все значения поля, тип результат []T
    	// - min(F) - минимальное значение поля, тип результат T
    	// - max(F) - максимальное значение поля, тип результат T
    	// - avg(F) - среднее значения поля, тип результат T
    	// - sum(F) - сумма значений поля, тип результат T
    	// - count() - число записей, тип результат int
    	Fields map[string]string
    }
    
    func MergeAggregateOptions(opts ...*AggregateOptions) *AggregateOptions {
    	o := &AggregateOptions{}
    	for _, opt := range opts {
    		if opt == nil {
    			continue
    		}
    		o.Options = MergeOptions(o.Options, opt.Options)
    
    		if o.Fields == nil {
    			o.Fields = opt.Fields
    			continue
    		}
    		for k, v := range opt.Fields {
    			o.Fields[k] = v
    		}
    	}
    	return o
    }
    
    type AggregatePublishedOptions AggregateOptions
    
    func (opts *AggregatePublishedOptions) ToAggregateOptions() *AggregateOptions {
    	return &AggregateOptions{
    		Options:     MergeOptions(opts.Options),
    		SortOptions: options.MergeSortOptions(opts.SortOptions),
    		Fields:      maps.Clone(opts.Fields),
    	}
    }
    
    func MergeAggregatePublishedOptions(opts ...*AggregatePublishedOptions) *AggregatePublishedOptions {
    	ao := make([]*AggregateOptions, len(opts))
    	for i, opt := range opts {
    		ao[i] = (*AggregateOptions)(opt)
    	}
    	merged := MergeAggregateOptions(ao...)
    	return (*AggregatePublishedOptions)(merged)
    }