github.com/go-generalize/volcago@v1.7.0/generator/testfiles/auto/task_gen.go (about)

     1  // Code generated by volcago. DO NOT EDIT.
     2  // generated version: devel
     3  package model
     4  
     5  import (
     6  	"context"
     7  
     8  	"cloud.google.com/go/firestore"
     9  	"github.com/go-utils/xim"
    10  	"golang.org/x/xerrors"
    11  	"google.golang.org/api/iterator"
    12  	"google.golang.org/grpc/codes"
    13  	"google.golang.org/grpc/status"
    14  )
    15  
    16  //go:generate mockgen -source $GOFILE -destination mock/mock_task_gen/mock_task_gen.go
    17  
    18  // TaskRepository - Repository of Task
    19  type TaskRepository interface {
    20  	// Single
    21  	Get(ctx context.Context, id string, opts ...GetOption) (*Task, error)
    22  	GetWithDoc(ctx context.Context, doc *firestore.DocumentRef, opts ...GetOption) (*Task, error)
    23  	Insert(ctx context.Context, subject *Task) (_ string, err error)
    24  	Update(ctx context.Context, subject *Task) (err error)
    25  	StrictUpdate(ctx context.Context, id string, param *TaskUpdateParam, opts ...firestore.Precondition) error
    26  	Delete(ctx context.Context, subject *Task, opts ...DeleteOption) (err error)
    27  	DeleteByID(ctx context.Context, id string, opts ...DeleteOption) (err error)
    28  	// Multiple
    29  	GetMulti(ctx context.Context, ids []string, opts ...GetOption) ([]*Task, error)
    30  	InsertMulti(ctx context.Context, subjects []*Task) (_ []string, er error)
    31  	UpdateMulti(ctx context.Context, subjects []*Task) (er error)
    32  	DeleteMulti(ctx context.Context, subjects []*Task, opts ...DeleteOption) (er error)
    33  	DeleteMultiByIDs(ctx context.Context, ids []string, opts ...DeleteOption) (er error)
    34  	// Single(Transaction)
    35  	GetWithTx(tx *firestore.Transaction, id string, opts ...GetOption) (*Task, error)
    36  	GetWithDocWithTx(tx *firestore.Transaction, doc *firestore.DocumentRef, opts ...GetOption) (*Task, error)
    37  	InsertWithTx(ctx context.Context, tx *firestore.Transaction, subject *Task) (_ string, err error)
    38  	UpdateWithTx(ctx context.Context, tx *firestore.Transaction, subject *Task) (err error)
    39  	StrictUpdateWithTx(tx *firestore.Transaction, id string, param *TaskUpdateParam, opts ...firestore.Precondition) error
    40  	DeleteWithTx(ctx context.Context, tx *firestore.Transaction, subject *Task, opts ...DeleteOption) (err error)
    41  	DeleteByIDWithTx(ctx context.Context, tx *firestore.Transaction, id string, opts ...DeleteOption) (err error)
    42  	// Multiple(Transaction)
    43  	GetMultiWithTx(tx *firestore.Transaction, ids []string, opts ...GetOption) ([]*Task, error)
    44  	InsertMultiWithTx(ctx context.Context, tx *firestore.Transaction, subjects []*Task) (_ []string, er error)
    45  	UpdateMultiWithTx(ctx context.Context, tx *firestore.Transaction, subjects []*Task) (er error)
    46  	DeleteMultiWithTx(ctx context.Context, tx *firestore.Transaction, subjects []*Task, opts ...DeleteOption) (er error)
    47  	DeleteMultiByIDsWithTx(ctx context.Context, tx *firestore.Transaction, ids []string, opts ...DeleteOption) (er error)
    48  	// Search
    49  	Search(ctx context.Context, param *TaskSearchParam, q *firestore.Query) ([]*Task, error)
    50  	SearchWithTx(tx *firestore.Transaction, param *TaskSearchParam, q *firestore.Query) ([]*Task, error)
    51  	SearchByParam(ctx context.Context, param *TaskSearchParam) ([]*Task, *PagingResult, error)
    52  	SearchByParamWithTx(tx *firestore.Transaction, param *TaskSearchParam) ([]*Task, *PagingResult, error)
    53  	// misc
    54  	GetCollection() *firestore.CollectionRef
    55  	GetCollectionName() string
    56  	GetDocRef(id string) *firestore.DocumentRef
    57  	RunInTransaction() func(ctx context.Context, f func(context.Context, *firestore.Transaction) error, opts ...firestore.TransactionOption) (err error)
    58  }
    59  
    60  // TaskRepositoryMiddleware - middleware of TaskRepository
    61  type TaskRepositoryMiddleware interface {
    62  	BeforeInsert(ctx context.Context, subject *Task) (bool, error)
    63  	BeforeUpdate(ctx context.Context, old, subject *Task) (bool, error)
    64  	BeforeDelete(ctx context.Context, subject *Task, opts ...DeleteOption) (bool, error)
    65  	BeforeDeleteByID(ctx context.Context, ids []string, opts ...DeleteOption) (bool, error)
    66  }
    67  
    68  type taskRepository struct {
    69  	collectionName   string
    70  	firestoreClient  *firestore.Client
    71  	middleware       []TaskRepositoryMiddleware
    72  	uniqueRepository *uniqueRepository
    73  }
    74  
    75  // NewTaskRepository - constructor
    76  func NewTaskRepository(firestoreClient *firestore.Client, middleware ...TaskRepositoryMiddleware) TaskRepository {
    77  	return &taskRepository{
    78  		collectionName:   "Task",
    79  		firestoreClient:  firestoreClient,
    80  		middleware:       middleware,
    81  		uniqueRepository: newUniqueRepository(firestoreClient, "Task"),
    82  	}
    83  }
    84  
    85  func (repo *taskRepository) beforeInsert(ctx context.Context, subject *Task) error {
    86  	repo.uniqueRepository.setMiddleware(ctx)
    87  	err := repo.uniqueRepository.CheckUnique(ctx, nil, subject)
    88  	if err != nil {
    89  		return xerrors.Errorf("unique.middleware error: %w", err)
    90  	}
    91  
    92  	for _, m := range repo.middleware {
    93  		c, err := m.BeforeInsert(ctx, subject)
    94  		if err != nil {
    95  			return xerrors.Errorf("beforeInsert.middleware error: %w", err)
    96  		}
    97  		if !c {
    98  			continue
    99  		}
   100  	}
   101  
   102  	return nil
   103  }
   104  
   105  func (repo *taskRepository) beforeUpdate(ctx context.Context, old, subject *Task) error {
   106  	if ctx.Value(transactionInProgressKey{}) != nil && old == nil {
   107  		var err error
   108  		doc := repo.GetDocRef(subject.ID)
   109  		old, err = repo.get(context.Background(), doc)
   110  		if err != nil {
   111  			if status.Code(err) == codes.NotFound {
   112  				return ErrNotFound
   113  			}
   114  			return xerrors.Errorf("error in Get method: %w", err)
   115  		}
   116  	}
   117  	repo.uniqueRepository.setMiddleware(ctx)
   118  	err := repo.uniqueRepository.CheckUnique(ctx, old, subject)
   119  	if err != nil {
   120  		return xerrors.Errorf("unique.middleware error: %w", err)
   121  	}
   122  
   123  	for _, m := range repo.middleware {
   124  		c, err := m.BeforeUpdate(ctx, old, subject)
   125  		if err != nil {
   126  			return xerrors.Errorf("beforeUpdate.middleware error: %w", err)
   127  		}
   128  		if !c {
   129  			continue
   130  		}
   131  	}
   132  
   133  	return nil
   134  }
   135  
   136  func (repo *taskRepository) beforeDelete(ctx context.Context, subject *Task, opts ...DeleteOption) error {
   137  	repo.uniqueRepository.setMiddleware(ctx)
   138  	err := repo.uniqueRepository.DeleteUnique(ctx, subject)
   139  	if err != nil {
   140  		return xerrors.Errorf("unique.middleware error: %w", err)
   141  	}
   142  
   143  	for _, m := range repo.middleware {
   144  		c, err := m.BeforeDelete(ctx, subject, opts...)
   145  		if err != nil {
   146  			return xerrors.Errorf("beforeDelete.middleware error: %w", err)
   147  		}
   148  		if !c {
   149  			continue
   150  		}
   151  	}
   152  
   153  	return nil
   154  }
   155  
   156  // GetCollection - *firestore.CollectionRef getter
   157  func (repo *taskRepository) GetCollection() *firestore.CollectionRef {
   158  	return repo.firestoreClient.Collection(repo.collectionName)
   159  }
   160  
   161  // GetCollectionName - CollectionName getter
   162  func (repo *taskRepository) GetCollectionName() string {
   163  	return repo.collectionName
   164  }
   165  
   166  // GetDocRef - *firestore.DocumentRef getter
   167  func (repo *taskRepository) GetDocRef(id string) *firestore.DocumentRef {
   168  	return repo.GetCollection().Doc(id)
   169  }
   170  
   171  // RunInTransaction - (*firestore.Client).RunTransaction getter
   172  func (repo *taskRepository) RunInTransaction() func(ctx context.Context, f func(context.Context, *firestore.Transaction) error, opts ...firestore.TransactionOption) (err error) {
   173  	return repo.firestoreClient.RunTransaction
   174  }
   175  
   176  func (repo *taskRepository) saveIndexes(subject *Task) error {
   177  	idx := xim.NewIndexes(&xim.Config{
   178  		IgnoreCase:         true,
   179  		SaveNoFiltersIndex: true,
   180  	})
   181  	{
   182  		idx.Add(TaskIndexLabelDescEqual, string(subject.Desc))
   183  		idx.AddBiunigrams(TaskIndexLabelDescLike, string(subject.Desc))
   184  		idx.AddPrefixes(TaskIndexLabelDescPrefix, string(subject.Desc))
   185  		idx.AddSuffixes(TaskIndexLabelDescSuffix, string(subject.Desc))
   186  		idx.AddSomething(TaskIndexLabelProportionEqual, subject.Proportion)
   187  	}
   188  	indexes, err := idx.Build()
   189  	if err != nil {
   190  		return xerrors.Errorf("failed to index build: %w", err)
   191  	} else if len(indexes) == 0 {
   192  		return nil
   193  	}
   194  
   195  	subject.Indexes = indexes
   196  
   197  	return nil
   198  }
   199  
   200  // TaskSearchParam - params for search
   201  type TaskSearchParam struct {
   202  	ID           *QueryChainer
   203  	Desc         *QueryChainer
   204  	Created      *QueryChainer
   205  	Done         *QueryChainer
   206  	Done2        *QueryChainer
   207  	Count        *QueryChainer
   208  	Count64      *QueryChainer
   209  	NameList     *QueryChainer
   210  	Proportion   *QueryChainer
   211  	Flag         *QueryChainer
   212  	SliceSubTask *QueryChainer
   213  
   214  	CursorKey   string
   215  	CursorLimit int
   216  }
   217  
   218  // TaskUpdateParam - params for strict updates
   219  type TaskUpdateParam struct {
   220  	Desc         interface{}
   221  	Created      interface{}
   222  	Done         interface{}
   223  	Done2        interface{}
   224  	Count        interface{}
   225  	Count64      interface{}
   226  	NameList     interface{}
   227  	Proportion   interface{}
   228  	Flag         interface{}
   229  	SliceSubTask interface{}
   230  }
   231  
   232  // Search - search documents
   233  // The third argument is firestore.Query, basically you can pass nil
   234  func (repo *taskRepository) Search(ctx context.Context, param *TaskSearchParam, q *firestore.Query) ([]*Task, error) {
   235  	return repo.search(ctx, param, q)
   236  }
   237  
   238  // SearchByParam - search documents by search param
   239  func (repo *taskRepository) SearchByParam(ctx context.Context, param *TaskSearchParam) ([]*Task, *PagingResult, error) {
   240  	return repo.searchByParam(ctx, param)
   241  }
   242  
   243  // Get - get `Task` by `Task.ID`
   244  func (repo *taskRepository) Get(ctx context.Context, id string, opts ...GetOption) (*Task, error) {
   245  	doc := repo.GetDocRef(id)
   246  	return repo.get(ctx, doc, opts...)
   247  }
   248  
   249  // GetWithDoc - get `Task` by *firestore.DocumentRef
   250  func (repo *taskRepository) GetWithDoc(ctx context.Context, doc *firestore.DocumentRef, opts ...GetOption) (*Task, error) {
   251  	return repo.get(ctx, doc, opts...)
   252  }
   253  
   254  // Insert - insert of `Task`
   255  func (repo *taskRepository) Insert(ctx context.Context, subject *Task) (_ string, err error) {
   256  	if err := repo.beforeInsert(ctx, subject); err != nil {
   257  		return "", xerrors.Errorf("before insert error: %w", err)
   258  	}
   259  
   260  	if err = repo.saveIndexes(subject); err != nil {
   261  		return "", xerrors.Errorf("failed to saveIndexes: %w", err)
   262  	}
   263  
   264  	return repo.insert(ctx, subject)
   265  }
   266  
   267  // Update - update of `Task`
   268  func (repo *taskRepository) Update(ctx context.Context, subject *Task) (err error) {
   269  	doc := repo.GetDocRef(subject.ID)
   270  
   271  	old, err := repo.get(ctx, doc)
   272  	if err != nil {
   273  		if status.Code(err) == codes.NotFound {
   274  			return ErrNotFound
   275  		}
   276  		return xerrors.Errorf("error in Get method: %w", err)
   277  	}
   278  
   279  	if err := repo.beforeUpdate(ctx, old, subject); err != nil {
   280  		return xerrors.Errorf("before update error: %w", err)
   281  	}
   282  
   283  	if err := repo.saveIndexes(subject); err != nil {
   284  		return xerrors.Errorf("failed to saveIndexes: %w", err)
   285  	}
   286  
   287  	return repo.update(ctx, subject)
   288  }
   289  
   290  // StrictUpdate - strict update of `Task`
   291  func (repo *taskRepository) StrictUpdate(ctx context.Context, id string, param *TaskUpdateParam, opts ...firestore.Precondition) error {
   292  	return repo.strictUpdate(ctx, id, param, opts...)
   293  }
   294  
   295  // Delete - delete of `Task`
   296  func (repo *taskRepository) Delete(ctx context.Context, subject *Task, opts ...DeleteOption) (err error) {
   297  	if err := repo.beforeDelete(ctx, subject, opts...); err != nil {
   298  		return xerrors.Errorf("before delete error: %w", err)
   299  	}
   300  
   301  	return repo.deleteByID(ctx, subject.ID)
   302  }
   303  
   304  // DeleteByID - delete `Task` by `Task.ID`
   305  func (repo *taskRepository) DeleteByID(ctx context.Context, id string, opts ...DeleteOption) (err error) {
   306  	subject, err := repo.Get(ctx, id)
   307  	if err != nil {
   308  		return xerrors.Errorf("error in Get method: %w", err)
   309  	}
   310  
   311  	if err := repo.beforeDelete(ctx, subject, opts...); err != nil {
   312  		return xerrors.Errorf("before delete error: %w", err)
   313  	}
   314  
   315  	return repo.Delete(ctx, subject, opts...)
   316  }
   317  
   318  // GetMulti - get `Task` in bulk by array of `Task.ID`
   319  func (repo *taskRepository) GetMulti(ctx context.Context, ids []string, opts ...GetOption) ([]*Task, error) {
   320  	return repo.getMulti(ctx, ids, opts...)
   321  }
   322  
   323  // InsertMulti - bulk insert of `Task`
   324  func (repo *taskRepository) InsertMulti(ctx context.Context, subjects []*Task) (_ []string, er error) {
   325  
   326  	ids := make([]string, 0, len(subjects))
   327  	batches := make([]*firestore.WriteBatch, 0)
   328  	batch := repo.firestoreClient.Batch()
   329  	collect := repo.GetCollection()
   330  
   331  	for i, subject := range subjects {
   332  		var ref *firestore.DocumentRef
   333  		if subject.ID == "" {
   334  			ref = collect.NewDoc()
   335  			subject.ID = ref.ID
   336  		} else {
   337  			ref = collect.Doc(subject.ID)
   338  			if s, err := ref.Get(ctx); err == nil {
   339  				return nil, xerrors.Errorf("already exists [%v]: %#v", subject.ID, s)
   340  			}
   341  		}
   342  
   343  		if err := repo.beforeInsert(ctx, subject); err != nil {
   344  			return nil, xerrors.Errorf("before insert error(%d) [%v]: %w", i, subject.ID, err)
   345  		}
   346  
   347  		if err := repo.saveIndexes(subjects[i]); err != nil {
   348  			return nil, xerrors.Errorf("failed to saveIndexes: %w", err)
   349  		}
   350  
   351  		batch.Set(ref, subject)
   352  		ids = append(ids, ref.ID)
   353  		i++
   354  		if (i%500) == 0 && len(subjects) != i {
   355  			batches = append(batches, batch)
   356  			batch = repo.firestoreClient.Batch()
   357  		}
   358  	}
   359  	batches = append(batches, batch)
   360  
   361  	for _, b := range batches {
   362  		if _, err := b.Commit(ctx); err != nil {
   363  			return nil, xerrors.Errorf("error in Commit method: %w", err)
   364  		}
   365  	}
   366  
   367  	return ids, nil
   368  }
   369  
   370  // UpdateMulti - bulk update of `Task`
   371  func (repo *taskRepository) UpdateMulti(ctx context.Context, subjects []*Task) (er error) {
   372  
   373  	batches := make([]*firestore.WriteBatch, 0)
   374  	batch := repo.firestoreClient.Batch()
   375  	collect := repo.GetCollection()
   376  
   377  	for i, subject := range subjects {
   378  		ref := collect.Doc(subject.ID)
   379  		snapShot, err := ref.Get(ctx)
   380  		if err != nil {
   381  			if status.Code(err) == codes.NotFound {
   382  				return xerrors.Errorf("not found [%v]: %w", subject.ID, err)
   383  			}
   384  			return xerrors.Errorf("error in Get method [%v]: %w", subject.ID, err)
   385  		}
   386  
   387  		old := new(Task)
   388  		if err = snapShot.DataTo(&old); err != nil {
   389  			return xerrors.Errorf("error in DataTo method: %w", err)
   390  		}
   391  
   392  		if err := repo.beforeUpdate(ctx, old, subject); err != nil {
   393  			return xerrors.Errorf("before update error(%d) [%v]: %w", i, subject.ID, err)
   394  		}
   395  
   396  		if err := repo.saveIndexes(subjects[i]); err != nil {
   397  			return xerrors.Errorf("failed to saveIndexes: %w", err)
   398  		}
   399  
   400  		batch.Set(ref, subject)
   401  		i++
   402  		if (i%500) == 0 && len(subjects) != i {
   403  			batches = append(batches, batch)
   404  			batch = repo.firestoreClient.Batch()
   405  		}
   406  	}
   407  	batches = append(batches, batch)
   408  
   409  	for _, b := range batches {
   410  		if _, err := b.Commit(ctx); err != nil {
   411  			return xerrors.Errorf("error in Commit method: %w", err)
   412  		}
   413  	}
   414  
   415  	return nil
   416  }
   417  
   418  // DeleteMulti - bulk delete of `Task`
   419  func (repo *taskRepository) DeleteMulti(ctx context.Context, subjects []*Task, opts ...DeleteOption) (er error) {
   420  
   421  	batches := make([]*firestore.WriteBatch, 0)
   422  	batch := repo.firestoreClient.Batch()
   423  	collect := repo.GetCollection()
   424  
   425  	for i, subject := range subjects {
   426  		ref := collect.Doc(subject.ID)
   427  		if _, err := ref.Get(ctx); err != nil {
   428  			if status.Code(err) == codes.NotFound {
   429  				return xerrors.Errorf("not found [%v]: %w", subject.ID, err)
   430  			}
   431  			return xerrors.Errorf("error in Get method [%v]: %w", subject.ID, err)
   432  		}
   433  
   434  		if err := repo.beforeDelete(ctx, subject, opts...); err != nil {
   435  			return xerrors.Errorf("before delete error(%d) [%v]: %w", i, subject.ID, err)
   436  		}
   437  
   438  		batch.Delete(ref)
   439  
   440  		i++
   441  		if (i%500) == 0 && len(subjects) != i {
   442  			batches = append(batches, batch)
   443  			batch = repo.firestoreClient.Batch()
   444  		}
   445  	}
   446  	batches = append(batches, batch)
   447  
   448  	for _, b := range batches {
   449  		if _, err := b.Commit(ctx); err != nil {
   450  			return xerrors.Errorf("error in Commit method: %w", err)
   451  		}
   452  	}
   453  
   454  	return nil
   455  }
   456  
   457  // DeleteMultiByIDs - delete `Task` in bulk by array of `Task.ID`
   458  func (repo *taskRepository) DeleteMultiByIDs(ctx context.Context, ids []string, opts ...DeleteOption) (er error) {
   459  	subjects := make([]*Task, len(ids))
   460  
   461  	opt := GetOption{}
   462  	if len(opts) > 0 {
   463  		opt.IncludeSoftDeleted = opts[0].Mode == DeleteModeHard
   464  	}
   465  	for i, id := range ids {
   466  		subject, err := repo.Get(ctx, id, opt)
   467  		if err != nil {
   468  			return xerrors.Errorf("error in Get method: %w", err)
   469  		}
   470  		subjects[i] = subject
   471  	}
   472  
   473  	return repo.DeleteMulti(ctx, subjects, opts...)
   474  }
   475  
   476  // SearchWithTx - search documents in transaction
   477  func (repo *taskRepository) SearchWithTx(tx *firestore.Transaction, param *TaskSearchParam, q *firestore.Query) ([]*Task, error) {
   478  	return repo.search(tx, param, q)
   479  }
   480  
   481  // SearchByParamWithTx - search documents by search param in transaction
   482  func (repo *taskRepository) SearchByParamWithTx(tx *firestore.Transaction, param *TaskSearchParam) ([]*Task, *PagingResult, error) {
   483  	return repo.searchByParam(tx, param)
   484  }
   485  
   486  // GetWithTx - get `Task` by `Task.ID` in transaction
   487  func (repo *taskRepository) GetWithTx(tx *firestore.Transaction, id string, opts ...GetOption) (*Task, error) {
   488  	doc := repo.GetDocRef(id)
   489  	return repo.get(tx, doc, opts...)
   490  }
   491  
   492  // GetWithDocWithTx - get `Task` by *firestore.DocumentRef in transaction
   493  func (repo *taskRepository) GetWithDocWithTx(tx *firestore.Transaction, doc *firestore.DocumentRef, opts ...GetOption) (*Task, error) {
   494  	return repo.get(tx, doc, opts...)
   495  }
   496  
   497  // InsertWithTx - insert of `Task` in transaction
   498  func (repo *taskRepository) InsertWithTx(ctx context.Context, tx *firestore.Transaction, subject *Task) (_ string, err error) {
   499  	if err := repo.beforeInsert(context.WithValue(ctx, transactionInProgressKey{}, tx), subject); err != nil {
   500  		return "", xerrors.Errorf("before insert error: %w", err)
   501  	}
   502  
   503  	if err := repo.saveIndexes(subject); err != nil {
   504  		return "", xerrors.Errorf("failed to saveIndexes: %w", err)
   505  	}
   506  
   507  	return repo.insert(tx, subject)
   508  }
   509  
   510  // UpdateWithTx - update of `Task` in transaction
   511  func (repo *taskRepository) UpdateWithTx(ctx context.Context, tx *firestore.Transaction, subject *Task) (err error) {
   512  	if err := repo.beforeUpdate(context.WithValue(ctx, transactionInProgressKey{}, tx), nil, subject); err != nil {
   513  		return xerrors.Errorf("before update error: %w", err)
   514  	}
   515  
   516  	if err := repo.saveIndexes(subject); err != nil {
   517  		return xerrors.Errorf("failed to saveIndexes: %w", err)
   518  	}
   519  
   520  	return repo.update(tx, subject)
   521  }
   522  
   523  // StrictUpdateWithTx - strict update of `Task` in transaction
   524  func (repo *taskRepository) StrictUpdateWithTx(tx *firestore.Transaction, id string, param *TaskUpdateParam, opts ...firestore.Precondition) error {
   525  	return repo.strictUpdate(tx, id, param, opts...)
   526  }
   527  
   528  // DeleteWithTx - delete of `Task` in transaction
   529  func (repo *taskRepository) DeleteWithTx(ctx context.Context, tx *firestore.Transaction, subject *Task, opts ...DeleteOption) (err error) {
   530  	if err := repo.beforeDelete(context.WithValue(ctx, transactionInProgressKey{}, tx), subject, opts...); err != nil {
   531  		return xerrors.Errorf("before delete error: %w", err)
   532  	}
   533  
   534  	return repo.deleteByID(tx, subject.ID)
   535  }
   536  
   537  // DeleteByIDWithTx - delete `Task` by `Task.ID` in transaction
   538  func (repo *taskRepository) DeleteByIDWithTx(ctx context.Context, tx *firestore.Transaction, id string, opts ...DeleteOption) (err error) {
   539  	subject, err := repo.Get(context.Background(), id)
   540  	if err != nil {
   541  		return xerrors.Errorf("error in Get method: %w", err)
   542  	}
   543  
   544  	if err := repo.beforeDelete(context.WithValue(ctx, transactionInProgressKey{}, tx), subject, opts...); err != nil {
   545  		return xerrors.Errorf("before delete error: %w", err)
   546  	}
   547  
   548  	return repo.deleteByID(tx, id)
   549  }
   550  
   551  // GetMultiWithTx - get `Task` in bulk by array of `Task.ID` in transaction
   552  func (repo *taskRepository) GetMultiWithTx(tx *firestore.Transaction, ids []string, opts ...GetOption) ([]*Task, error) {
   553  	return repo.getMulti(tx, ids, opts...)
   554  }
   555  
   556  // InsertMultiWithTx - bulk insert of `Task` in transaction
   557  func (repo *taskRepository) InsertMultiWithTx(ctx context.Context, tx *firestore.Transaction, subjects []*Task) (_ []string, er error) {
   558  
   559  	ids := make([]string, len(subjects))
   560  
   561  	for i := range subjects {
   562  		if err := repo.beforeInsert(ctx, subjects[i]); err != nil {
   563  			return nil, xerrors.Errorf("before insert error(%d) [%v]: %w", i, subjects[i].ID, err)
   564  		}
   565  
   566  		if err := repo.saveIndexes(subjects[i]); err != nil {
   567  			return nil, xerrors.Errorf("failed to saveIndexes: %w", err)
   568  		}
   569  
   570  		id, err := repo.insert(tx, subjects[i])
   571  		if err != nil {
   572  			return nil, xerrors.Errorf("error in insert method(%d) [%v]: %w", i, subjects[i].ID, err)
   573  		}
   574  		ids[i] = id
   575  	}
   576  
   577  	return ids, nil
   578  }
   579  
   580  // UpdateMultiWithTx - bulk update of `Task` in transaction
   581  func (repo *taskRepository) UpdateMultiWithTx(ctx context.Context, tx *firestore.Transaction, subjects []*Task) (er error) {
   582  	ctx = context.WithValue(ctx, transactionInProgressKey{}, tx)
   583  
   584  	for i := range subjects {
   585  		if err := repo.beforeUpdate(ctx, nil, subjects[i]); err != nil {
   586  			return xerrors.Errorf("before update error(%d) [%v]: %w", i, subjects[i].ID, err)
   587  		}
   588  	}
   589  
   590  	for i := range subjects {
   591  		if err := repo.saveIndexes(subjects[i]); err != nil {
   592  			return xerrors.Errorf("failed to saveIndexes: %w", err)
   593  		}
   594  		if err := repo.update(tx, subjects[i]); err != nil {
   595  			return xerrors.Errorf("error in update method(%d) [%v]: %w", i, subjects[i].ID, err)
   596  		}
   597  	}
   598  
   599  	return nil
   600  }
   601  
   602  // DeleteMultiWithTx - bulk delete of `Task` in transaction
   603  func (repo *taskRepository) DeleteMultiWithTx(ctx context.Context, tx *firestore.Transaction, subjects []*Task, opts ...DeleteOption) (er error) {
   604  
   605  	var isHardDeleteMode bool
   606  	if len(opts) > 0 {
   607  		isHardDeleteMode = opts[0].Mode == DeleteModeHard
   608  	}
   609  	opt := GetOption{
   610  		IncludeSoftDeleted: isHardDeleteMode,
   611  	}
   612  	for i := range subjects {
   613  		dr := repo.GetDocRef(subjects[i].ID)
   614  		if _, err := repo.get(context.Background(), dr, opt); err != nil {
   615  			if status.Code(err) == codes.NotFound {
   616  				return xerrors.Errorf("not found(%d) [%v]", i, subjects[i].ID)
   617  			}
   618  			return xerrors.Errorf("error in get method(%d) [%v]: %w", i, subjects[i].ID, err)
   619  		}
   620  
   621  		if err := repo.beforeDelete(context.WithValue(ctx, transactionInProgressKey{}, tx), subjects[i], opts...); err != nil {
   622  			return xerrors.Errorf("before delete error(%d) [%v]: %w", i, subjects[i].ID, err)
   623  		}
   624  	}
   625  
   626  	for i := range subjects {
   627  		if err := repo.deleteByID(tx, subjects[i].ID); err != nil {
   628  			return xerrors.Errorf("error in delete method(%d) [%v]: %w", i, subjects[i].ID, err)
   629  		}
   630  	}
   631  
   632  	return nil
   633  }
   634  
   635  // DeleteMultiByIDWithTx - delete `Task` in bulk by array of `Task.ID` in transaction
   636  func (repo *taskRepository) DeleteMultiByIDsWithTx(ctx context.Context, tx *firestore.Transaction, ids []string, opts ...DeleteOption) (er error) {
   637  
   638  	for i := range ids {
   639  		dr := repo.GetDocRef(ids[i])
   640  		subject, err := repo.get(context.Background(), dr)
   641  		if err != nil {
   642  			if status.Code(err) == codes.NotFound {
   643  				return xerrors.Errorf("not found(%d) [%v]", i, ids[i])
   644  			}
   645  			return xerrors.Errorf("error in get method(%d) [%v]: %w", i, ids[i], err)
   646  		}
   647  
   648  		if err := repo.beforeDelete(context.WithValue(ctx, transactionInProgressKey{}, tx), subject, opts...); err != nil {
   649  			return xerrors.Errorf("before delete error(%d) [%v]: %w", i, subject.ID, err)
   650  		}
   651  	}
   652  
   653  	for i := range ids {
   654  		if err := repo.deleteByID(tx, ids[i]); err != nil {
   655  			return xerrors.Errorf("error in delete method(%d) [%v]: %w", i, ids[i], err)
   656  		}
   657  	}
   658  
   659  	return nil
   660  }
   661  
   662  func (repo *taskRepository) get(v interface{}, doc *firestore.DocumentRef, _ ...GetOption) (*Task, error) {
   663  	var (
   664  		snapShot *firestore.DocumentSnapshot
   665  		err      error
   666  	)
   667  
   668  	switch x := v.(type) {
   669  	case *firestore.Transaction:
   670  		snapShot, err = x.Get(doc)
   671  	case context.Context:
   672  		snapShot, err = doc.Get(x)
   673  	default:
   674  		return nil, xerrors.Errorf("invalid type: %v", x)
   675  	}
   676  
   677  	if err != nil {
   678  		if status.Code(err) == codes.NotFound {
   679  			return nil, ErrNotFound
   680  		}
   681  		return nil, xerrors.Errorf("error in Get method: %w", err)
   682  	}
   683  
   684  	subject := new(Task)
   685  	if err := snapShot.DataTo(&subject); err != nil {
   686  		return nil, xerrors.Errorf("error in DataTo method: %w", err)
   687  	}
   688  
   689  	subject.ID = snapShot.Ref.ID
   690  
   691  	return subject, nil
   692  }
   693  
   694  func (repo *taskRepository) getMulti(v interface{}, ids []string, _ ...GetOption) ([]*Task, error) {
   695  	var (
   696  		snapShots []*firestore.DocumentSnapshot
   697  		err       error
   698  		collect   = repo.GetCollection()
   699  		drs       = make([]*firestore.DocumentRef, len(ids))
   700  	)
   701  
   702  	for i, id := range ids {
   703  		ref := collect.Doc(id)
   704  		drs[i] = ref
   705  	}
   706  
   707  	switch x := v.(type) {
   708  	case *firestore.Transaction:
   709  		snapShots, err = x.GetAll(drs)
   710  	case context.Context:
   711  		snapShots, err = repo.firestoreClient.GetAll(x, drs)
   712  	default:
   713  		return nil, xerrors.Errorf("invalid type: %v", v)
   714  	}
   715  
   716  	if err != nil {
   717  		return nil, xerrors.Errorf("error in GetAll method: %w", err)
   718  	}
   719  
   720  	subjects := make([]*Task, 0, len(ids))
   721  	mErr := NewMultiErrors()
   722  	for i, snapShot := range snapShots {
   723  		if !snapShot.Exists() {
   724  			mErr = append(mErr, NewMultiError(i, ErrNotFound))
   725  			continue
   726  		}
   727  
   728  		subject := new(Task)
   729  		if err = snapShot.DataTo(&subject); err != nil {
   730  			return nil, xerrors.Errorf("error in DataTo method: %w", err)
   731  		}
   732  
   733  		subject.ID = snapShot.Ref.ID
   734  		subjects = append(subjects, subject)
   735  	}
   736  
   737  	if len(mErr) == 0 {
   738  		return subjects, nil
   739  	}
   740  
   741  	return subjects, mErr
   742  }
   743  
   744  func (repo *taskRepository) insert(v interface{}, subject *Task) (string, error) {
   745  	var (
   746  		dr  = repo.GetCollection().NewDoc()
   747  		err error
   748  	)
   749  
   750  	switch x := v.(type) {
   751  	case *firestore.Transaction:
   752  		err = x.Create(dr, subject)
   753  	case context.Context:
   754  		_, err = dr.Create(x, subject)
   755  	default:
   756  		return "", xerrors.Errorf("invalid type: %v", v)
   757  	}
   758  
   759  	if err != nil {
   760  		if status.Code(err) == codes.AlreadyExists {
   761  			return "", xerrors.Errorf("error in Create method: err=%+v: %w", err, ErrAlreadyExists)
   762  		}
   763  		return "", xerrors.Errorf("error in Create method: %w", err)
   764  	}
   765  
   766  	subject.ID = dr.ID
   767  
   768  	return dr.ID, nil
   769  }
   770  
   771  func (repo *taskRepository) update(v interface{}, subject *Task) error {
   772  	var (
   773  		dr  = repo.GetDocRef(subject.ID)
   774  		err error
   775  	)
   776  
   777  	switch x := v.(type) {
   778  	case *firestore.Transaction:
   779  		err = x.Set(dr, subject)
   780  	case context.Context:
   781  		_, err = dr.Set(x, subject)
   782  	default:
   783  		return xerrors.Errorf("invalid type: %v", v)
   784  	}
   785  
   786  	if err != nil {
   787  		return xerrors.Errorf("error in Set method: %w", err)
   788  	}
   789  
   790  	return nil
   791  }
   792  
   793  func (repo *taskRepository) strictUpdate(v interface{}, id string, param *TaskUpdateParam, opts ...firestore.Precondition) error {
   794  	var (
   795  		dr  = repo.GetDocRef(id)
   796  		err error
   797  	)
   798  
   799  	updates := updater(Task{}, param)
   800  
   801  	switch x := v.(type) {
   802  	case *firestore.Transaction:
   803  		err = x.Update(dr, updates, opts...)
   804  	case context.Context:
   805  		_, err = dr.Update(x, updates, opts...)
   806  	default:
   807  		return xerrors.Errorf("invalid type: %v", v)
   808  	}
   809  
   810  	if err != nil {
   811  		return xerrors.Errorf("error in Update method: %w", err)
   812  	}
   813  
   814  	return nil
   815  }
   816  
   817  func (repo *taskRepository) deleteByID(v interface{}, id string) error {
   818  	dr := repo.GetDocRef(id)
   819  	var err error
   820  
   821  	switch x := v.(type) {
   822  	case *firestore.Transaction:
   823  		err = x.Delete(dr, firestore.Exists)
   824  	case context.Context:
   825  		_, err = dr.Delete(x, firestore.Exists)
   826  	default:
   827  		return xerrors.Errorf("invalid type: %v", v)
   828  	}
   829  
   830  	if err != nil {
   831  		return xerrors.Errorf("error in Delete method: %w", err)
   832  	}
   833  
   834  	return nil
   835  }
   836  
   837  func (repo *taskRepository) runQuery(v interface{}, query firestore.Query) ([]*Task, error) {
   838  	var iter *firestore.DocumentIterator
   839  
   840  	switch x := v.(type) {
   841  	case *firestore.Transaction:
   842  		iter = x.Documents(query)
   843  	case context.Context:
   844  		iter = query.Documents(x)
   845  	default:
   846  		return nil, xerrors.Errorf("invalid type: %v", v)
   847  	}
   848  
   849  	defer iter.Stop()
   850  
   851  	subjects := make([]*Task, 0)
   852  
   853  	for {
   854  		doc, err := iter.Next()
   855  		if err == iterator.Done {
   856  			break
   857  		}
   858  		if err != nil {
   859  			return nil, xerrors.Errorf("error in Next method: %w", err)
   860  		}
   861  
   862  		subject := new(Task)
   863  
   864  		if err = doc.DataTo(&subject); err != nil {
   865  			return nil, xerrors.Errorf("error in DataTo method: %w", err)
   866  		}
   867  
   868  		subject.ID = doc.Ref.ID
   869  		subjects = append(subjects, subject)
   870  	}
   871  
   872  	return subjects, nil
   873  }
   874  
   875  // BUG(54m): there may be potential bugs
   876  func (repo *taskRepository) searchByParam(v interface{}, param *TaskSearchParam) ([]*Task, *PagingResult, error) {
   877  	query := func() firestore.Query {
   878  		return repo.GetCollection().Query
   879  	}()
   880  	filters := xim.NewFilters(&xim.Config{
   881  		IgnoreCase:         true,
   882  		SaveNoFiltersIndex: true,
   883  	})
   884  
   885  	if param.ID != nil {
   886  		for _, chain := range param.ID.QueryGroup {
   887  			var value interface{}
   888  			switch val := chain.Value.(type) {
   889  			case string:
   890  				value = repo.GetDocRef(val)
   891  			case []string:
   892  				docRefs := make([]*firestore.DocumentRef, len(val))
   893  				for i := range val {
   894  					docRefs[i] = repo.GetDocRef(val[i])
   895  				}
   896  				value = docRefs
   897  			default:
   898  				return nil, nil, xerrors.Errorf("document id can only be of type `string` and `[]string`. value: %#v", chain.Value)
   899  			}
   900  			query = query.Where(firestore.DocumentID, chain.Operator, value)
   901  		}
   902  		if direction := param.ID.OrderByDirection; direction > 0 {
   903  			query = query.OrderBy(firestore.DocumentID, direction)
   904  			query = param.ID.BuildCursorQuery(query)
   905  		}
   906  	}
   907  	if param.Desc != nil {
   908  		for _, chain := range param.Desc.QueryGroup {
   909  			query = query.Where("description", chain.Operator, chain.Value)
   910  		}
   911  		if direction := param.Desc.OrderByDirection; direction > 0 {
   912  			query = query.OrderBy("description", direction)
   913  			query = param.Desc.BuildCursorQuery(query)
   914  		}
   915  		value, ok := param.Desc.Filter.Value.(string)
   916  		// The value of the "indexer" tag = "e,p,s,l"
   917  		// Add/AddBiunigrams/AddPrefix/AddSuffix is valid.
   918  		for _, filter := range param.Desc.Filter.FilterTypes {
   919  			switch filter {
   920  			case FilterTypeAddBiunigrams:
   921  				if ok {
   922  					filters.AddBiunigrams(TaskIndexLabelDescLike, value)
   923  				}
   924  			case FilterTypeAddPrefix:
   925  				if ok {
   926  					filters.AddPrefix(TaskIndexLabelDescPrefix, value)
   927  				}
   928  			case FilterTypeAddSuffix:
   929  				if ok {
   930  					filters.AddSuffix(TaskIndexLabelDescSuffix, value)
   931  				}
   932  			// Treat `Add` or otherwise as `Equal`.
   933  			case FilterTypeAdd:
   934  				fallthrough
   935  			default:
   936  				if !ok {
   937  					filters.AddSomething(TaskIndexLabelDescEqual, param.Desc.Filter.Value)
   938  					continue
   939  				}
   940  				filters.Add(TaskIndexLabelDescEqual, value)
   941  			}
   942  		}
   943  	}
   944  	if param.Created != nil {
   945  		for _, chain := range param.Created.QueryGroup {
   946  			query = query.Where("created", chain.Operator, chain.Value)
   947  		}
   948  		if direction := param.Created.OrderByDirection; direction > 0 {
   949  			query = query.OrderBy("created", direction)
   950  			query = param.Created.BuildCursorQuery(query)
   951  		}
   952  		value, ok := param.Created.Filter.Value.(string)
   953  		for _, filter := range param.Created.Filter.FilterTypes {
   954  			switch filter {
   955  			// Treat `Add` or otherwise as `Equal`.
   956  			case FilterTypeAdd:
   957  				fallthrough
   958  			default:
   959  				if !ok {
   960  					filters.AddSomething(TaskIndexLabelCreatedEqual, param.Created.Filter.Value)
   961  					continue
   962  				}
   963  				filters.Add(TaskIndexLabelCreatedEqual, value)
   964  			}
   965  		}
   966  	}
   967  	if param.Done != nil {
   968  		for _, chain := range param.Done.QueryGroup {
   969  			query = query.Where("done", chain.Operator, chain.Value)
   970  		}
   971  		if direction := param.Done.OrderByDirection; direction > 0 {
   972  			query = query.OrderBy("done", direction)
   973  			query = param.Done.BuildCursorQuery(query)
   974  		}
   975  		value, ok := param.Done.Filter.Value.(string)
   976  		for _, filter := range param.Done.Filter.FilterTypes {
   977  			switch filter {
   978  			// Treat `Add` or otherwise as `Equal`.
   979  			case FilterTypeAdd:
   980  				fallthrough
   981  			default:
   982  				if !ok {
   983  					filters.AddSomething(TaskIndexLabelDoneEqual, param.Done.Filter.Value)
   984  					continue
   985  				}
   986  				filters.Add(TaskIndexLabelDoneEqual, value)
   987  			}
   988  		}
   989  	}
   990  	if param.Done2 != nil {
   991  		for _, chain := range param.Done2.QueryGroup {
   992  			query = query.Where("done2", chain.Operator, chain.Value)
   993  		}
   994  		if direction := param.Done2.OrderByDirection; direction > 0 {
   995  			query = query.OrderBy("done2", direction)
   996  			query = param.Done2.BuildCursorQuery(query)
   997  		}
   998  		value, ok := param.Done2.Filter.Value.(string)
   999  		for _, filter := range param.Done2.Filter.FilterTypes {
  1000  			switch filter {
  1001  			// Treat `Add` or otherwise as `Equal`.
  1002  			case FilterTypeAdd:
  1003  				fallthrough
  1004  			default:
  1005  				if !ok {
  1006  					filters.AddSomething(TaskIndexLabelDone2Equal, param.Done2.Filter.Value)
  1007  					continue
  1008  				}
  1009  				filters.Add(TaskIndexLabelDone2Equal, value)
  1010  			}
  1011  		}
  1012  	}
  1013  	if param.Count != nil {
  1014  		for _, chain := range param.Count.QueryGroup {
  1015  			query = query.Where("count", chain.Operator, chain.Value)
  1016  		}
  1017  		if direction := param.Count.OrderByDirection; direction > 0 {
  1018  			query = query.OrderBy("count", direction)
  1019  			query = param.Count.BuildCursorQuery(query)
  1020  		}
  1021  		value, ok := param.Count.Filter.Value.(string)
  1022  		for _, filter := range param.Count.Filter.FilterTypes {
  1023  			switch filter {
  1024  			// Treat `Add` or otherwise as `Equal`.
  1025  			case FilterTypeAdd:
  1026  				fallthrough
  1027  			default:
  1028  				if !ok {
  1029  					filters.AddSomething(TaskIndexLabelCountEqual, param.Count.Filter.Value)
  1030  					continue
  1031  				}
  1032  				filters.Add(TaskIndexLabelCountEqual, value)
  1033  			}
  1034  		}
  1035  	}
  1036  	if param.Count64 != nil {
  1037  		for _, chain := range param.Count64.QueryGroup {
  1038  			query = query.Where("count64", chain.Operator, chain.Value)
  1039  		}
  1040  		if direction := param.Count64.OrderByDirection; direction > 0 {
  1041  			query = query.OrderBy("count64", direction)
  1042  			query = param.Count64.BuildCursorQuery(query)
  1043  		}
  1044  		value, ok := param.Count64.Filter.Value.(string)
  1045  		for _, filter := range param.Count64.Filter.FilterTypes {
  1046  			switch filter {
  1047  			// Treat `Add` or otherwise as `Equal`.
  1048  			case FilterTypeAdd:
  1049  				fallthrough
  1050  			default:
  1051  				if !ok {
  1052  					filters.AddSomething(TaskIndexLabelCount64Equal, param.Count64.Filter.Value)
  1053  					continue
  1054  				}
  1055  				filters.Add(TaskIndexLabelCount64Equal, value)
  1056  			}
  1057  		}
  1058  	}
  1059  	if param.NameList != nil {
  1060  		for _, chain := range param.NameList.QueryGroup {
  1061  			query = query.Where("nameList", chain.Operator, chain.Value)
  1062  		}
  1063  	}
  1064  	if param.Proportion != nil {
  1065  		for _, chain := range param.Proportion.QueryGroup {
  1066  			query = query.Where("proportion", chain.Operator, chain.Value)
  1067  		}
  1068  		if direction := param.Proportion.OrderByDirection; direction > 0 {
  1069  			query = query.OrderBy("proportion", direction)
  1070  			query = param.Proportion.BuildCursorQuery(query)
  1071  		}
  1072  		value, ok := param.Proportion.Filter.Value.(string)
  1073  		// The value of the "indexer" tag = "e"
  1074  		for _, filter := range param.Proportion.Filter.FilterTypes {
  1075  			switch filter {
  1076  			// Treat `Add` or otherwise as `Equal`.
  1077  			case FilterTypeAdd:
  1078  				fallthrough
  1079  			default:
  1080  				if !ok {
  1081  					filters.AddSomething(TaskIndexLabelProportionEqual, param.Proportion.Filter.Value)
  1082  					continue
  1083  				}
  1084  				filters.Add(TaskIndexLabelProportionEqual, value)
  1085  			}
  1086  		}
  1087  	}
  1088  	if param.Flag != nil {
  1089  		for _, chain := range param.Flag.QueryGroup {
  1090  			items, ok := chain.Value.(map[string]float64)
  1091  			if !ok {
  1092  				continue
  1093  			}
  1094  			for key, value := range items {
  1095  				query = query.WherePath(firestore.FieldPath{"flag", key}, chain.Operator, value)
  1096  			}
  1097  		}
  1098  	}
  1099  	if param.SliceSubTask != nil {
  1100  		for _, chain := range param.SliceSubTask.QueryGroup {
  1101  			query = query.Where("slice_sub_task", chain.Operator, chain.Value)
  1102  		}
  1103  	}
  1104  
  1105  	build, err := filters.Build()
  1106  	if err != nil {
  1107  		return nil, nil, xerrors.Errorf("failed to filter build: %w", err)
  1108  	}
  1109  	for key := range build {
  1110  		query = query.WherePath(firestore.FieldPath{"indexes", key}, OpTypeEqual, true)
  1111  	}
  1112  
  1113  	limit := param.CursorLimit + 1
  1114  
  1115  	if param.CursorKey != "" {
  1116  		var (
  1117  			ds  *firestore.DocumentSnapshot
  1118  			err error
  1119  		)
  1120  		switch x := v.(type) {
  1121  		case *firestore.Transaction:
  1122  			ds, err = x.Get(repo.GetDocRef(param.CursorKey))
  1123  		case context.Context:
  1124  			ds, err = repo.GetDocRef(param.CursorKey).Get(x)
  1125  		default:
  1126  			return nil, nil, xerrors.Errorf("invalid x type: %v", v)
  1127  		}
  1128  		if err != nil {
  1129  			if status.Code(err) == codes.NotFound {
  1130  				return nil, nil, ErrNotFound
  1131  			}
  1132  			return nil, nil, xerrors.Errorf("error in Get method: %w", err)
  1133  		}
  1134  		query = query.StartAt(ds)
  1135  	}
  1136  
  1137  	if limit > 1 {
  1138  		query = query.Limit(limit)
  1139  	}
  1140  
  1141  	subjects, err := repo.runQuery(v, query)
  1142  	if err != nil {
  1143  		return nil, nil, xerrors.Errorf("error in runQuery method: %w", err)
  1144  	}
  1145  
  1146  	pagingResult := &PagingResult{
  1147  		Length: len(subjects),
  1148  	}
  1149  	if limit > 1 && limit == pagingResult.Length {
  1150  		next := pagingResult.Length - 1
  1151  		pagingResult.NextCursorKey = subjects[next].ID
  1152  		subjects = subjects[:next]
  1153  		pagingResult.Length--
  1154  	}
  1155  
  1156  	return subjects, pagingResult, nil
  1157  }
  1158  
  1159  func (repo *taskRepository) search(v interface{}, param *TaskSearchParam, q *firestore.Query) ([]*Task, error) {
  1160  	if (param == nil && q == nil) || (param != nil && q != nil) {
  1161  		return nil, xerrors.New("either one should be nil")
  1162  	}
  1163  
  1164  	query := func() firestore.Query {
  1165  		if q != nil {
  1166  			return *q
  1167  		}
  1168  		return repo.GetCollection().Query
  1169  	}()
  1170  
  1171  	if q == nil {
  1172  		subjects, _, err := repo.searchByParam(v, param)
  1173  		if err != nil {
  1174  			return nil, xerrors.Errorf("error in searchByParam method: %w", err)
  1175  		}
  1176  
  1177  		return subjects, nil
  1178  	}
  1179  
  1180  	return repo.runQuery(v, query)
  1181  }