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