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

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